From 33aae6e709ddf9884b329066c3df2dc6e20698b6 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Mon, 29 Jul 2024 16:13:08 +0800 Subject: [PATCH] List installed tools when no command is provided to `uv tool run` --- crates/uv-cli/src/lib.rs | 3 +- crates/uv/src/commands/tool/run.rs | 9 ++++-- crates/uv/src/settings.rs | 2 +- crates/uv/tests/tool_run.rs | 45 ++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 42732d07233f..e481229daa8f 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -2264,8 +2264,9 @@ pub struct ToolRunArgs { /// /// If more complex version specification is desired or if the command is provided by a different /// package, use `--from`. + /// If no command is given, should list installed tools and treat it as `uv tool list` #[command(subcommand)] - pub command: ExternalCommand, + pub command: Option, /// Use the given package to provide the command. /// diff --git a/crates/uv/src/commands/tool/run.rs b/crates/uv/src/commands/tool/run.rs index 0dab15151a5a..efc4a7eae590 100644 --- a/crates/uv/src/commands/tool/run.rs +++ b/crates/uv/src/commands/tool/run.rs @@ -31,7 +31,7 @@ use crate::commands::reporters::PythonDownloadReporter; use crate::commands::project::resolve_names; use crate::commands::{ - project, project::environment::CachedEnvironment, tool::common::matching_packages, + project, project::environment::CachedEnvironment, tool::common::matching_packages, tool_list, }; use crate::commands::{ExitStatus, SharedState}; use crate::printer::Printer; @@ -56,7 +56,7 @@ impl Display for ToolRunCommand { /// Run a command. pub(crate) async fn run( - command: ExternalCommand, + command: Option, from: Option, with: &[RequirementsSource], python: Option, @@ -76,6 +76,11 @@ pub(crate) async fn run( warn_user_once!("`{invocation_source}` is experimental and may change without warning"); } + // treat empty command as `uv tool list` + let Some(command) = command else { + return tool_list(false, PreviewMode::Enabled, cache, printer).await; + }; + let (target, args) = command.split(); let Some(target) = target else { return Err(anyhow::anyhow!("No tool command provided")); diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 9c3dedd54945..f6e014cdb59d 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -251,7 +251,7 @@ impl RunSettings { #[allow(clippy::struct_excessive_bools)] #[derive(Debug, Clone)] pub(crate) struct ToolRunSettings { - pub(crate) command: ExternalCommand, + pub(crate) command: Option, pub(crate) from: Option, pub(crate) with: Vec, pub(crate) with_requirements: Vec, diff --git a/crates/uv/tests/tool_run.rs b/crates/uv/tests/tool_run.rs index 939ea1235b9a..8bb97fbcfcbb 100644 --- a/crates/uv/tests/tool_run.rs +++ b/crates/uv/tests/tool_run.rs @@ -766,3 +766,48 @@ fn tool_run_requirements_txt_arguments() { + werkzeug==3.0.1 "###); } + +/// List installed tools when no command arg is given (e.g. `uv tool run`). +#[test] +fn tool_run_list_installed() { + let context = TestContext::new("3.12").with_filtered_exe_suffix(); + let tool_dir = context.temp_dir.child("tools"); + let bin_dir = context.temp_dir.child("bin"); + + // No tools installed. + uv_snapshot!(context.filters(), context.tool_run() + .env("UV_TOOL_DIR", tool_dir.as_os_str()) + .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + warning: `uv tool run` is experimental and may change without warning + No tools installed + "###); + + // Install `black`. + context + .tool_install() + .arg("black==24.2.0") + .env("UV_TOOL_DIR", tool_dir.as_os_str()) + .env("XDG_BIN_HOME", bin_dir.as_os_str()) + .assert() + .success(); + + // List installed tools. + uv_snapshot!(context.filters(), context.tool_run() + .env("UV_TOOL_DIR", tool_dir.as_os_str()) + .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" + success: true + exit_code: 0 + ----- stdout ----- + black v24.2.0 + - black + - blackd + + ----- stderr ----- + warning: `uv tool run` is experimental and may change without warning + "###); +}