Skip to content

Commit

Permalink
List installed tools when no command is provided to uv tool run (#5553
Browse files Browse the repository at this point in the history
)

## Summary

Part of #4024 

## Test Plan

Test cases included.
  • Loading branch information
eth3lbert authored Jul 29, 2024
1 parent ecb85c9 commit 3e32902
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 4 deletions.
4 changes: 3 additions & 1 deletion crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2264,8 +2264,10 @@ pub struct ToolRunArgs {
///
/// If more complex version specification is desired or if the command is provided by a different
/// package, use `--from`.
///
/// If omitted, lists the available tools.
#[command(subcommand)]
pub command: ExternalCommand,
pub command: Option<ExternalCommand>,

/// Use the given package to provide the command.
///
Expand Down
9 changes: 7 additions & 2 deletions crates/uv/src/commands/tool/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -56,7 +56,7 @@ impl Display for ToolRunCommand {

/// Run a command.
pub(crate) async fn run(
command: ExternalCommand,
command: Option<ExternalCommand>,
from: Option<String>,
with: &[RequirementsSource],
python: Option<String>,
Expand All @@ -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"));
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ExternalCommand>,
pub(crate) from: Option<String>,
pub(crate) with: Vec<String>,
pub(crate) with_requirements: Vec<PathBuf>,
Expand Down
45 changes: 45 additions & 0 deletions crates/uv/tests/tool_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
"###);
}

0 comments on commit 3e32902

Please sign in to comment.