From a84c95527a0bd47403b33616f2cc6d9e78590992 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Thu, 5 Sep 2024 22:20:42 -0700 Subject: [PATCH] Use an option instead. --- CHANGELOG.md | 12 +++++---- crates/cli/src/commands/alias.rs | 8 +++--- crates/cli/src/commands/install.rs | 26 ++++++------------ crates/cli/src/commands/pin.rs | 32 +++++++++++----------- crates/cli/src/commands/plugin/add.rs | 7 ++--- crates/cli/src/commands/plugin/remove.rs | 31 ++++++++++----------- crates/cli/src/commands/unalias.rs | 8 +++--- crates/cli/src/commands/unpin.rs | 8 +++--- crates/cli/src/helpers.rs | 29 ++++++++++++++++++++ crates/cli/tests/alias_test.rs | 5 ++-- crates/cli/tests/pin_test.rs | 6 ++++- crates/cli/tests/plugin_add_test.rs | 32 ++++++++++++++++++++++ crates/cli/tests/plugin_remove_test.rs | 34 ++++++++++++++++++++++++ crates/cli/tests/unalias_test.rs | 6 ++++- crates/cli/tests/unpin_test.rs | 27 +++++++++++++++++++ crates/core/src/proto.rs | 8 ------ crates/core/src/proto_config.rs | 2 +- 17 files changed, 199 insertions(+), 82 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10da81285..0278ab7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,11 +15,13 @@ #### 🚀 Updates - Added support for updating the `~/.prototools` file (root of user home directory). - - Added `--pin=user` to `proto install`. - - Added `--user` to `proto alias`, `unalias`, `pin`, `unpin`, `plugin add`, and `plugin remove`. - - Added `store` as an alias for `global`. - - Added `cwd` as an alias for `local`. - - Added `home` as an alias for `user`. +- Added `--pin=user` to `proto install`. +- Added `--to=global|local|user` to `proto alias`, `pin`, and `plugin add`. +- Added `--from=global|local|user` to `proto unalias`, `unpin`, and `plugin remove`. +- Added aliases for pin locations. + - `cwd` -> `local` + - `home` -> `user` + - `store` -> `global` - Added new `settings.offline` settings that control how offline checks work. #### ⚙️ Internal diff --git a/crates/cli/src/commands/alias.rs b/crates/cli/src/commands/alias.rs index 2fa30a6d9..b1381cf56 100644 --- a/crates/cli/src/commands/alias.rs +++ b/crates/cli/src/commands/alias.rs @@ -1,4 +1,5 @@ use crate::error::ProtoCliError; +use crate::helpers::{map_pin_type, PinOption}; use crate::session::ProtoSession; use clap::Args; use proto_core::{is_alias_name, Id, ProtoConfig, UnresolvedVersionSpec}; @@ -19,8 +20,8 @@ pub struct AliasArgs { #[arg(long, group = "pin", help = "Add to the global ~/.proto/.prototools")] global: bool, - #[arg(long, group = "pin", help = "Add to the user ~/.prototools")] - user: bool, + #[arg(long, group = "pin", help = "Location of .prototools to add to")] + to: Option, } #[tracing::instrument(skip_all)] @@ -41,7 +42,8 @@ pub async fn alias(session: ProtoSession, args: AliasArgs) -> AppResult { let tool = session.load_tool(&args.id).await?; let config_path = ProtoConfig::update( - tool.proto.get_config_dir_from_flags(args.global, args.user), + tool.proto + .get_config_dir(map_pin_type(args.global, args.to)), |config| { let tool_configs = config.tools.get_or_insert(Default::default()); diff --git a/crates/cli/src/commands/install.rs b/crates/cli/src/commands/install.rs index 83a5d4b3b..0dfe152a6 100644 --- a/crates/cli/src/commands/install.rs +++ b/crates/cli/src/commands/install.rs @@ -3,7 +3,7 @@ use crate::helpers::*; use crate::session::ProtoSession; use crate::shell::{self, Export}; use crate::telemetry::{track_usage, Metric}; -use clap::{Args, ValueEnum}; +use clap::Args; use indicatif::ProgressBar; use miette::IntoDiagnostic; use proto_core::flow::install::{InstallOptions, InstallPhase}; @@ -19,16 +19,6 @@ use tokio::task::JoinSet; use tokio::time::sleep; use tracing::{debug, instrument}; -#[derive(Clone, Debug, ValueEnum)] -pub enum PinOption { - #[value(alias = "store")] - Global, - #[value(alias = "cwd")] - Local, - #[value(alias = "home")] - User, -} - #[derive(Args, Clone, Debug, Default)] pub struct InstallArgs { #[arg(help = "ID of a single tool to install")] @@ -87,30 +77,30 @@ async fn pin_version( ) -> miette::Result { let config = tool.proto.load_config()?; let spec = tool.get_resolved_version().to_unresolved_spec(); - let mut global = false; + let mut pin_type = PinType::Local; let mut pin = false; // via `--pin` arg - if let Some(pin_type) = arg_pin_type { - global = matches!(pin_type, PinType::Global); + if let Some(custom_type) = arg_pin_type { + pin_type = *custom_type; pin = true; } // Or the first time being installed else if !config.versions.contains_key(&tool.id) { - global = true; + pin_type = PinType::Global; pin = true; } // via `pin-latest` setting if initial_version.is_latest() { - if let Some(pin_type) = &config.settings.pin_latest { - global = matches!(pin_type, PinType::Global); + if let Some(custom_type) = &config.settings.pin_latest { + pin_type = *custom_type; pin = true; } } if pin { - internal_pin(tool, &spec, global, false, true).await?; + internal_pin(tool, &spec, pin_type, true).await?; } Ok(pin) diff --git a/crates/cli/src/commands/pin.rs b/crates/cli/src/commands/pin.rs index d8ca03552..fc8d96981 100644 --- a/crates/cli/src/commands/pin.rs +++ b/crates/cli/src/commands/pin.rs @@ -1,6 +1,7 @@ +use crate::helpers::{map_pin_type, PinOption}; use crate::session::ProtoSession; use clap::Args; -use proto_core::{Id, ProtoConfig, Tool, UnresolvedVersionSpec}; +use proto_core::{Id, PinType, ProtoConfig, Tool, UnresolvedVersionSpec}; use starbase::AppResult; use starbase_styles::color; use std::collections::BTreeMap; @@ -18,34 +19,30 @@ pub struct PinArgs { #[arg(long, group = "pin", help = "Pin to the global ~/.proto/.prototools")] pub global: bool, - #[arg(long, group = "pin", help = "Pin to the user ~/.prototools")] - pub user: bool, - #[arg(long, help = "Resolve the version before pinning")] pub resolve: bool, + + #[arg(long, group = "pin", help = "Location of .prototools to pin to")] + pub to: Option, } pub async fn internal_pin( tool: &mut Tool, spec: &UnresolvedVersionSpec, - global: bool, - user: bool, + pin: PinType, link: bool, ) -> miette::Result { // Create symlink to this new version - if global && link { + if pin == PinType::Global && link { tool.symlink_bins(true).await?; } - let config_path = ProtoConfig::update( - tool.proto.get_config_dir_from_flags(global, user), - |config| { - config - .versions - .get_or_insert(BTreeMap::default()) - .insert(tool.id.clone(), spec.clone()); - }, - )?; + let config_path = ProtoConfig::update(tool.proto.get_config_dir(pin), |config| { + config + .versions + .get_or_insert(BTreeMap::default()) + .insert(tool.id.clone(), spec.clone()); + })?; debug!( version = spec.to_string(), @@ -67,7 +64,8 @@ pub async fn pin(session: ProtoSession, args: PinArgs) -> AppResult { args.spec.clone() }; - let config_path = internal_pin(&mut tool, &spec, args.global, args.user, false).await?; + let config_path = + internal_pin(&mut tool, &spec, map_pin_type(args.global, args.to), false).await?; println!( "Pinned {} to {} in {}", diff --git a/crates/cli/src/commands/plugin/add.rs b/crates/cli/src/commands/plugin/add.rs index 1946ab93a..6f4d234d4 100644 --- a/crates/cli/src/commands/plugin/add.rs +++ b/crates/cli/src/commands/plugin/add.rs @@ -1,3 +1,4 @@ +use crate::helpers::{map_pin_type, PinOption}; use crate::session::ProtoSession; use clap::Args; use proto_core::{Id, PluginLocator, ProtoConfig}; @@ -15,8 +16,8 @@ pub struct AddPluginArgs { #[arg(long, group = "pin", help = "Add to the global ~/.proto/.prototools")] global: bool, - #[arg(long, group = "pin", help = "Add to the user ~/.prototools")] - user: bool, + #[arg(long, group = "pin", help = "Location of .prototools to add to")] + to: Option, } #[tracing::instrument(skip_all)] @@ -24,7 +25,7 @@ pub async fn add(session: ProtoSession, args: AddPluginArgs) -> AppResult { let config_path = ProtoConfig::update( session .env - .get_config_dir_from_flags(args.global, args.user), + .get_config_dir(map_pin_type(args.global, args.to)), |config| { config .plugins diff --git a/crates/cli/src/commands/plugin/remove.rs b/crates/cli/src/commands/plugin/remove.rs index 313504a26..891221dec 100644 --- a/crates/cli/src/commands/plugin/remove.rs +++ b/crates/cli/src/commands/plugin/remove.rs @@ -1,4 +1,5 @@ use crate::error::ProtoCliError; +use crate::helpers::{map_pin_type, PinOption}; use crate::session::ProtoSession; use clap::Args; use proto_core::{Id, ProtoConfig, PROTO_CONFIG_NAME}; @@ -17,30 +18,26 @@ pub struct RemovePluginArgs { )] global: bool, - #[arg(long, group = "pin", help = "Remove from the user ~/.prototools")] - user: bool, + #[arg(long, group = "pin", help = "Location of .prototools to remove from")] + from: Option, } #[tracing::instrument(skip_all)] pub async fn remove(session: ProtoSession, args: RemovePluginArgs) -> AppResult { - if !args.global { - let config_path = session.env.cwd.join(PROTO_CONFIG_NAME); + let config_dir = session + .env + .get_config_dir(map_pin_type(args.global, args.from)); + let config_path = config_dir.join(PROTO_CONFIG_NAME); - if !config_path.exists() { - return Err(ProtoCliError::MissingToolsConfigInCwd { path: config_path }.into()); - } + if !config_path.exists() { + return Err(ProtoCliError::MissingToolsConfigInCwd { path: config_path }.into()); } - let config_path = ProtoConfig::update( - session - .env - .get_config_dir_from_flags(args.global, args.user), - |config| { - if let Some(plugins) = &mut config.plugins { - plugins.remove(&args.id); - } - }, - )?; + let config_path = ProtoConfig::update(config_dir, |config| { + if let Some(plugins) = &mut config.plugins { + plugins.remove(&args.id); + } + })?; println!( "Removed plugin {} from config {}", diff --git a/crates/cli/src/commands/unalias.rs b/crates/cli/src/commands/unalias.rs index 9c28a5967..2a029ba98 100644 --- a/crates/cli/src/commands/unalias.rs +++ b/crates/cli/src/commands/unalias.rs @@ -1,3 +1,4 @@ +use crate::helpers::{map_pin_type, PinOption}; use crate::session::ProtoSession; use clap::Args; use proto_core::{Id, ProtoConfig}; @@ -20,8 +21,8 @@ pub struct UnaliasArgs { )] global: bool, - #[arg(long, group = "pin", help = "Remove from the user ~/.prototools")] - user: bool, + #[arg(long, group = "pin", help = "Location of .prototools to remove from")] + from: Option, } #[tracing::instrument(skip_all)] @@ -30,7 +31,8 @@ pub async fn unalias(session: ProtoSession, args: UnaliasArgs) -> AppResult { let mut value = None; let config_path = ProtoConfig::update( - tool.proto.get_config_dir_from_flags(args.global, args.user), + tool.proto + .get_config_dir(map_pin_type(args.global, args.from)), |config| { if let Some(tool_configs) = &mut config.tools { if let Some(tool_config) = tool_configs.get_mut(&tool.id) { diff --git a/crates/cli/src/commands/unpin.rs b/crates/cli/src/commands/unpin.rs index f0688f143..be1dbd030 100644 --- a/crates/cli/src/commands/unpin.rs +++ b/crates/cli/src/commands/unpin.rs @@ -1,3 +1,4 @@ +use crate::helpers::{map_pin_type, PinOption}; use crate::session::ProtoSession; use clap::Args; use proto_core::{Id, ProtoConfig}; @@ -17,8 +18,8 @@ pub struct UnpinArgs { )] pub global: bool, - #[arg(long, group = "pin", help = "Unpin from the user ~/.prototools")] - pub user: bool, + #[arg(long, group = "pin", help = "Location of .prototools to unpin from")] + pub from: Option, } #[tracing::instrument(skip_all)] @@ -27,7 +28,8 @@ pub async fn unpin(session: ProtoSession, args: UnpinArgs) -> AppResult { let mut value = None; let config_path = ProtoConfig::update( - tool.proto.get_config_dir_from_flags(args.global, args.user), + tool.proto + .get_config_dir(map_pin_type(args.global, args.from)), |config| { if let Some(versions) = &mut config.versions { value = versions.remove(&tool.id); diff --git a/crates/cli/src/helpers.rs b/crates/cli/src/helpers.rs index 1eb5c0861..e3082d131 100644 --- a/crates/cli/src/helpers.rs +++ b/crates/cli/src/helpers.rs @@ -1,14 +1,43 @@ +use clap::ValueEnum; use dialoguer::{ console::{style, Style}, theme::ColorfulTheme, }; use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle}; use miette::IntoDiagnostic; +use proto_core::PinType; use starbase_styles::color::{self, Color}; use starbase_utils::env::bool_var; use std::{io::IsTerminal, time::Duration}; use tracing::debug; +#[derive(Clone, Copy, Debug, Default, ValueEnum)] +pub enum PinOption { + #[value(alias = "store")] + Global, + #[default] + #[value(alias = "cwd")] + Local, + #[value(alias = "home")] + User, +} + +pub fn map_pin_type(global: bool, option: Option) -> PinType { + if let Some(option) = option { + return match option { + PinOption::Global => PinType::Global, + PinOption::Local => PinType::Local, + PinOption::User => PinType::User, + }; + } + + if global { + PinType::Global + } else { + PinType::Local + } +} + pub fn create_theme() -> ColorfulTheme { ColorfulTheme { defaults_style: Style::new().for_stderr().color256(Color::Pink as u8), diff --git a/crates/cli/tests/alias_test.rs b/crates/cli/tests/alias_test.rs index e26a64149..602522980 100644 --- a/crates/cli/tests/alias_test.rs +++ b/crates/cli/tests/alias_test.rs @@ -163,9 +163,10 @@ mod alias_user { .arg("node") .arg("example") .arg("19.0.0") - .arg("--user"); + .arg("--to") + .arg("user"); }) - .debug(); + .success(); assert!(config_file.exists()); diff --git a/crates/cli/tests/pin_test.rs b/crates/cli/tests/pin_test.rs index 606152869..71ce40ca6 100644 --- a/crates/cli/tests/pin_test.rs +++ b/crates/cli/tests/pin_test.rs @@ -266,7 +266,11 @@ mod pin_user { sandbox .run_bin(|cmd| { - cmd.arg("pin").arg("node").arg("19.0.0").arg("--user"); + cmd.arg("pin") + .arg("node") + .arg("19.0.0") + .arg("--to") + .arg("home"); }) .success(); diff --git a/crates/cli/tests/plugin_add_test.rs b/crates/cli/tests/plugin_add_test.rs index 2580a9f2e..c12fbb254 100644 --- a/crates/cli/tests/plugin_add_test.rs +++ b/crates/cli/tests/plugin_add_test.rs @@ -83,4 +83,36 @@ mod plugin_add { })) ); } + + #[test] + fn updates_user_file() { + let sandbox = create_empty_proto_sandbox(); + let config_file = sandbox.path().join(".home/.prototools"); + + assert!(!config_file.exists()); + + sandbox + .run_bin(|cmd| { + cmd.arg("plugin") + .arg("add") + .arg("id") + .arg("https://github.com/moonrepo/tools/releases/latest/download/example_plugin.wasm") + .arg("--to") + .arg("user"); + }) + .success(); + + assert!(config_file.exists()); + + let config = load_config(sandbox.path().join(".home")); + + assert_eq!( + config.plugins.get("id").unwrap(), + &PluginLocator::Url(Box::new(UrlLocator { + url: + "https://github.com/moonrepo/tools/releases/latest/download/example_plugin.wasm" + .into() + })) + ); + } } diff --git a/crates/cli/tests/plugin_remove_test.rs b/crates/cli/tests/plugin_remove_test.rs index 1cadc235e..64af64797 100644 --- a/crates/cli/tests/plugin_remove_test.rs +++ b/crates/cli/tests/plugin_remove_test.rs @@ -75,4 +75,38 @@ mod plugin_remove { assert!(!config.plugins.contains_key("id")); } + + #[test] + fn updates_user_file() { + let sandbox = create_empty_proto_sandbox(); + + ProtoConfig::update(sandbox.path().join(".home"), |config| { + config + .plugins + .get_or_insert(Default::default()) + .insert( + Id::raw("id"), + PluginLocator::Url(Box::new(UrlLocator { + url: "https://github.com/moonrepo/tools/releases/latest/download/example_plugin.wasm".into() + })), + ); + }) + .unwrap(); + + sandbox.debug_files(); + + sandbox + .run_bin(|cmd| { + cmd.arg("plugin") + .arg("remove") + .arg("id") + .arg("--from") + .arg("user"); + }) + .success(); + + let config = load_config(sandbox.path().join(".home")); + + assert!(!config.plugins.contains_key("id")); + } } diff --git a/crates/cli/tests/unalias_test.rs b/crates/cli/tests/unalias_test.rs index f1a8d4515..bb435c19f 100644 --- a/crates/cli/tests/unalias_test.rs +++ b/crates/cli/tests/unalias_test.rs @@ -147,7 +147,11 @@ mod unalias_user { sandbox .run_bin(|cmd| { - cmd.arg("unalias").arg("node").arg("example").arg("--user"); + cmd.arg("unalias") + .arg("node") + .arg("example") + .arg("--from") + .arg("user"); }) .success(); diff --git a/crates/cli/tests/unpin_test.rs b/crates/cli/tests/unpin_test.rs index 2e731f445..7cc7b3ea8 100644 --- a/crates/cli/tests/unpin_test.rs +++ b/crates/cli/tests/unpin_test.rs @@ -97,3 +97,30 @@ mod unpin_global { assert!(!config.versions.contains_key("node")); } } + +mod unpin_user { + use super::*; + + #[test] + fn removes_existing_pin() { + let sandbox = create_empty_proto_sandbox(); + + ProtoConfig::update(sandbox.path().join(".home"), |config| { + config + .versions + .get_or_insert(Default::default()) + .insert(Id::raw("node"), UnresolvedVersionSpec::Canary); + }) + .unwrap(); + + sandbox + .run_bin(|cmd| { + cmd.arg("unpin").arg("node").arg("--from").arg("user"); + }) + .success(); + + let config = load_config(sandbox.path().join(".home")); + + assert!(!config.versions.contains_key("node")); + } +} diff --git a/crates/core/src/proto.rs b/crates/core/src/proto.rs index 277079b18..772271e75 100644 --- a/crates/core/src/proto.rs +++ b/crates/core/src/proto.rs @@ -71,14 +71,6 @@ impl ProtoEnvironment { } } - pub fn get_config_dir_from_flags(&self, global: bool, user: bool) -> &Path { - match (global, user) { - (true, false) => self.get_config_dir(PinType::Global), - (false, true) => self.get_config_dir(PinType::User), - _ => self.get_config_dir(PinType::Local), - } - } - pub fn get_plugin_loader(&self) -> miette::Result<&PluginLoader> { let config = self.load_config()?; diff --git a/crates/core/src/proto_config.rs b/crates/core/src/proto_config.rs index b60c50b90..446f27fe5 100644 --- a/crates/core/src/proto_config.rs +++ b/crates/core/src/proto_config.rs @@ -120,7 +120,7 @@ derive_enum!( ); derive_enum!( - #[derive(ConfigEnum)] + #[derive(Copy, ConfigEnum)] pub enum PinType { #[serde(alias = "store")] Global,