From 0f98717598d59d848d895bd2be4acff9dd55fb5c Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Sat, 7 Dec 2024 17:21:40 -0800 Subject: [PATCH] Polish. --- crates/cli/src/commands/activate.rs | 30 ++++---- crates/cli/src/commands/bin.rs | 23 ++++-- crates/cli/src/commands/completions.rs | 14 +++- crates/cli/src/commands/install.rs | 100 ++++++++++++++++++------- crates/cli/src/commands/pin.rs | 4 +- crates/cli/src/commands/regen.rs | 10 +-- crates/cli/src/commands/run.rs | 8 +- 7 files changed, 128 insertions(+), 61 deletions(-) diff --git a/crates/cli/src/commands/activate.rs b/crates/cli/src/commands/activate.rs index 136ef1ee6..49c385f15 100644 --- a/crates/cli/src/commands/activate.rs +++ b/crates/cli/src/commands/activate.rs @@ -2,7 +2,7 @@ use crate::session::ProtoSession; use clap::Args; use indexmap::IndexMap; use miette::IntoDiagnostic; -use proto_core::{detect_version, ConfigMode, Id, UnresolvedVersionSpec}; +use proto_core::{detect_version, Id, UnresolvedVersionSpec}; use serde::Serialize; use starbase::AppResult; use starbase_shell::{Hook, ShellType, Statement}; @@ -78,7 +78,7 @@ pub async fn activate(session: ProtoSession, args: ActivateArgs) -> AppResult { // If not exporting data, just print the activation syntax immediately if !args.export && !args.json { - return print_activation_hook(&shell_type, &args, session.cli.config_mode.as_ref()); + return print_activation_hook(&session, &shell_type, &args); } // Pre-load configuration @@ -167,7 +167,7 @@ pub async fn activate(session: ProtoSession, args: ActivateArgs) -> AppResult { // Output/export the information for the chosen shell if args.export { - print_activation_exports(&shell_type, info)?; + print_activation_exports(&session, &shell_type, info)?; return Ok(None); } @@ -182,13 +182,13 @@ pub async fn activate(session: ProtoSession, args: ActivateArgs) -> AppResult { } fn print_activation_hook( + session: &ProtoSession, shell_type: &ShellType, args: &ActivateArgs, - config_mode: Option<&ConfigMode>, ) -> AppResult { let mut command = format!("proto activate {}", shell_type); - if let Some(mode) = config_mode { + if let Some(mode) = &session.cli.config_mode { command.push_str(" --config-mode "); command.push_str(&mode.to_string()); } @@ -212,22 +212,26 @@ fn print_activation_hook( } }; - println!( - "{}", - shell_type.build().format_hook(Hook::OnChangeDir { + session + .console + .out + .write_line(shell_type.build().format_hook(Hook::OnChangeDir { command, function: "_proto_activate_hook".into(), - })? - ); + })?)?; if args.on_init { - println!("\n_proto_activate_hook"); + session.console.out.write_line("\n_proto_activate_hook")?; } Ok(None) } -fn print_activation_exports(shell_type: &ShellType, info: ActivateInfo) -> AppResult { +fn print_activation_exports( + session: &ProtoSession, + shell_type: &ShellType, + info: ActivateInfo, +) -> AppResult { let shell = shell_type.build(); let mut output = vec![]; @@ -253,7 +257,7 @@ fn print_activation_exports(shell_type: &ShellType, info: ActivateInfo) -> AppRe })); } - println!("{}", output.join("\n")); + session.console.out.write_line(output.join("\n"))?; Ok(None) } diff --git a/crates/cli/src/commands/bin.rs b/crates/cli/src/commands/bin.rs index 28b034f34..089367a27 100644 --- a/crates/cli/src/commands/bin.rs +++ b/crates/cli/src/commands/bin.rs @@ -22,12 +22,12 @@ pub struct BinArgs { #[tracing::instrument(skip_all)] pub async fn bin(session: ProtoSession, args: BinArgs) -> AppResult { if args.id == PROTO_PLUGIN_KEY { - println!( - "{}", + session.console.out.write_line( locate_proto_exe("proto") .unwrap_or(session.env.store.bin_dir.join(get_exe_file_name("proto"))) .display() - ); + .to_string(), + )?; return Ok(None); } @@ -42,7 +42,11 @@ pub async fn bin(session: ProtoSession, args: BinArgs) -> AppResult { for bin in tool.resolve_bin_locations(false).await? { if bin.config.primary { - println!("{}", bin.path.display()); + session + .console + .out + .write_line(bin.path.display().to_string())?; + return Ok(None); } } @@ -53,13 +57,20 @@ pub async fn bin(session: ProtoSession, args: BinArgs) -> AppResult { for shim in tool.resolve_shim_locations().await? { if shim.config.primary { - println!("{}", shim.path.display()); + session + .console + .out + .write_line(shim.path.display().to_string())?; + return Ok(None); } } } - println!("{}", tool.locate_exe_file().await?.display()); + session + .console + .out + .write_line(tool.locate_exe_file().await?.display().to_string())?; Ok(None) } diff --git a/crates/cli/src/commands/completions.rs b/crates/cli/src/commands/completions.rs index 7c146bf1e..83fe4232a 100644 --- a/crates/cli/src/commands/completions.rs +++ b/crates/cli/src/commands/completions.rs @@ -3,7 +3,9 @@ use crate::session::ProtoSession; use clap::{Args, CommandFactory}; use clap_complete::{generate, Shell}; use clap_complete_nushell::Nushell; +use iocraft::prelude::element; use starbase::AppResult; +use starbase_console::ui::*; use starbase_shell::ShellType; #[derive(Args, Clone, Debug)] @@ -13,7 +15,7 @@ pub struct CompletionsArgs { } #[tracing::instrument(skip_all)] -pub async fn completions(_session: ProtoSession, args: CompletionsArgs) -> AppResult { +pub async fn completions(session: ProtoSession, args: CompletionsArgs) -> AppResult { let shell = match args.shell { Some(value) => value, None => ShellType::try_detect()?, @@ -34,7 +36,15 @@ pub async fn completions(_session: ProtoSession, args: CompletionsArgs) -> AppRe return Ok(None); } unsupported => { - eprintln!("{unsupported} does not currently support completions"); + session.console.render(element! { + Notice(variant: Variant::Caution) { + StyledText( + content: format!( + "{unsupported} does not currently support completions", + ), + ) + } + })?; return Ok(Some(1)); } diff --git a/crates/cli/src/commands/install.rs b/crates/cli/src/commands/install.rs index 1f1e9259d..64d143518 100644 --- a/crates/cli/src/commands/install.rs +++ b/crates/cli/src/commands/install.rs @@ -7,10 +7,14 @@ use crate::telemetry::{track_usage, Metric}; use crate::utils::install_graph::*; use clap::Args; use indicatif::ProgressBar; +use iocraft::prelude::{element, Box as UiBox}; use proto_core::flow::install::{InstallOptions, InstallPhase}; -use proto_core::{Id, PinLocation, Tool, UnresolvedVersionSpec, VersionSpec, PROTO_PLUGIN_KEY}; +use proto_core::{ + ConfigMode, Id, PinLocation, Tool, UnresolvedVersionSpec, VersionSpec, PROTO_PLUGIN_KEY, +}; use proto_pdk_api::{InstallHook, SyncShellProfileInput, SyncShellProfileOutput}; use starbase::AppResult; +use starbase_console::ui::*; use starbase_shell::ShellType; use starbase_styles::color; use std::collections::BTreeMap; @@ -60,7 +64,7 @@ pub struct InstallArgs { } impl InstallArgs { - fn get_pin_type(&self) -> Option { + fn get_pin_location(&self) -> Option { self.pin.as_ref().map(|pin| match pin { Some(PinOption::Global) => PinLocation::Global, Some(PinOption::User) => PinLocation::User, @@ -97,7 +101,7 @@ pub fn enforce_requirements( async fn pin_version( tool: &mut Tool, initial_version: &UnresolvedVersionSpec, - arg_pin_type: &Option, + arg_pin_to: &Option, ) -> miette::Result { // Don't pin the proto tool itself as it's internal only if tool.id.as_str() == PROTO_PLUGIN_KEY { @@ -106,30 +110,30 @@ async fn pin_version( let config = tool.proto.load_config()?; let spec = tool.get_resolved_version().to_unresolved_spec(); - let mut pin_type = PinLocation::Local; + let mut pin_to = PinLocation::Local; let mut pin = false; // via `--pin` arg - if let Some(custom_type) = arg_pin_type { - pin_type = *custom_type; + if let Some(custom_type) = arg_pin_to { + pin_to = *custom_type; pin = true; } // Or the first time being installed - else if !config.versions.contains_key(&tool.id) { - pin_type = PinLocation::Global; + else if !tool.inventory.dir.exists() { + pin_to = PinLocation::Global; pin = true; } // via `pin-latest` setting if initial_version.is_latest() { if let Some(custom_type) = &config.settings.pin_latest { - pin_type = *custom_type; + pin_to = *custom_type; pin = true; } } if pin { - internal_pin(tool, &spec, pin_type).await?; + internal_pin(tool, &spec, pin_to).await?; } Ok(pin) @@ -202,7 +206,7 @@ async fn update_shell(tool: &Tool, passthrough_args: Vec) -> miette::Res &exported_content, &output.check_var, )? { - println!( + debug!( "Added {} to shell profile {}", color::property(output.check_var), color::path(updated_profile) @@ -220,7 +224,7 @@ pub async fn do_install( pb: &ProgressBar, ) -> miette::Result { let version = args.get_unresolved_spec(); - let pin_type = args.get_pin_type(); + let pin_type = args.get_pin_location(); let name = tool.get_name().to_owned(); let finish_pb = |installed: bool, resolved_version: &VersionSpec| { @@ -390,26 +394,38 @@ async fn install_one(session: &ProtoSession, id: &Id, args: InstallArgs) -> miet // Load config including global versions, // so that our requirements can be satisfied - let config = session.env.load_config_manager()?.get_merged_config()?; + let config = session.load_config_with_mode(ConfigMode::UpwardsGlobal)?; enforce_requirements(&tool, &config.versions)?; let pb = create_progress_bar(format!("Installing {}", tool.get_name())); if do_install(&mut tool, args, &pb).await? { - println!( - "{} {} has been installed to {}!", - tool.get_name(), - tool.get_resolved_version(), - color::path(tool.get_product_dir()), - ); + session.console.render(element! { + Notice(variant: Variant::Success) { + StyledText( + content: format!( + "{} {} has been installed to {}!", + tool.get_name(), + tool.get_resolved_version(), + tool.get_product_dir().display(), + ), + ) + } + })?; } else { - println!( - "{} {} has already been installed at {}", - tool.get_name(), - tool.get_resolved_version(), - color::path(tool.get_product_dir()), - ); + session.console.render(element! { + Notice(variant: Variant::Info) { + StyledText( + content: format!( + "{} {} has already been installed at {}!", + tool.get_name(), + tool.get_resolved_version(), + tool.get_product_dir().display(), + ), + ) + } + })?; } Ok(tool.tool) @@ -423,7 +439,7 @@ pub async fn install_all(session: &ProtoSession) -> AppResult { debug!("Detecting tool versions to install"); - let mut versions = session.env.load_config()?.versions.to_owned(); + let mut versions = session.load_config()?.versions.to_owned(); versions.remove(PROTO_PLUGIN_KEY); for tool in &tools { @@ -439,7 +455,27 @@ pub async fn install_all(session: &ProtoSession) -> AppResult { } if versions.is_empty() { - eprintln!("No versions have been configured, nothing to install!"); + session.console.render(element! { + Notice(variant: Variant::Caution) { + StyledText( + content: "No versions have been configured, nothing to install!", + ) + #(if session.env.config_mode == ConfigMode::UpwardsGlobal { + None + } else { + Some(element! { + UiBox(margin_top: 1) { + StyledText( + content: format!( + "Configuration has been loaded in {} mode. Try changing the mode with --config-mode to include other pinned versions.", + session.env.config_mode + ) + ) + } + }) + }) + } + })?; return Ok(Some(1)); } @@ -564,11 +600,17 @@ pub async fn install_all(session: &ProtoSession) -> AppResult { // When no TTY, we should display something to the user! if mpb.is_hidden() { if installed_count > 0 { - println!("Successfully installed {} tools!", installed_count); + session + .console + .out + .write_line(format!("Successfully installed {} tools!", installed_count))?; } if failed_count > 0 { - println!("Failed to install {} tools!", failed_count); + session + .console + .out + .write_line(format!("Failed to install {} tools!", failed_count))?; } } diff --git a/crates/cli/src/commands/pin.rs b/crates/cli/src/commands/pin.rs index c637d1b59..47619dc60 100644 --- a/crates/cli/src/commands/pin.rs +++ b/crates/cli/src/commands/pin.rs @@ -27,9 +27,9 @@ pub struct PinArgs { pub async fn internal_pin( tool: &mut Tool, spec: &UnresolvedVersionSpec, - pin: PinLocation, + pin_to: PinLocation, ) -> miette::Result { - let config_path = ProtoConfig::update(tool.proto.get_config_dir(pin), |config| { + let config_path = ProtoConfig::update(tool.proto.get_config_dir(pin_to), |config| { config .versions .get_or_insert(BTreeMap::default()) diff --git a/crates/cli/src/commands/regen.rs b/crates/cli/src/commands/regen.rs index b66fb8cfe..9b33efa12 100644 --- a/crates/cli/src/commands/regen.rs +++ b/crates/cli/src/commands/regen.rs @@ -14,11 +14,11 @@ pub struct RegenArgs { pub async fn regen(session: ProtoSession, args: RegenArgs) -> AppResult { let store = &session.env.store; - if args.bin { - println!("Regenerating bins and shims..."); + session.console.out.write_line(if args.bin { + "Regenerating bins and shims..." } else { - println!("Regenerating shims..."); - } + "Regenerating shims..." + })?; // Delete all shims debug!("Removing old shims"); @@ -67,7 +67,7 @@ pub async fn regen(session: ProtoSession, args: RegenArgs) -> AppResult { } } - println!("Regeneration complete!"); + session.console.out.write_line("Regeneration complete!")?; Ok(None) } diff --git a/crates/cli/src/commands/run.rs b/crates/cli/src/commands/run.rs index 3a30fa976..42d785d9a 100644 --- a/crates/cli/src/commands/run.rs +++ b/crates/cli/src/commands/run.rs @@ -179,11 +179,11 @@ pub async fn run(session: ProtoSession, args: RunArgs) -> AppResult { } // Install the tool - println!( + session.console.out.write_line(format!( "Auto-install is enabled, attempting to install {} {}", tool.get_name(), resolved_version, - ); + ))?; let install_args = InstallArgs { id: Some(tool.id.clone()), @@ -195,11 +195,11 @@ pub async fn run(session: ProtoSession, args: RunArgs) -> AppResult { do_install(&mut tool, install_args, &pb).await?; - println!( + session.console.out.write_line(format!( "{} {} has been installed, continuing execution...", tool.get_name(), resolved_version, - ); + ))?; } // Determine the binary path to execute