diff --git a/crates/uv/src/commands/tool/list.rs b/crates/uv/src/commands/tool/list.rs index 793beba59a5e..4f5c4c165a8a 100644 --- a/crates/uv/src/commands/tool/list.rs +++ b/crates/uv/src/commands/tool/list.rs @@ -39,12 +39,8 @@ pub(crate) async fn list( return Ok(ExitStatus::Success); } - writeln!( - printer.stdout(), - "Provide a command to invoke with `uvx ` or `uvx --from `.\n\n\ - The following tools are already installed:\n" - )?; - + // Create a string buffer and aggregate the tools with their versions, and entry points + let mut buffer = String::new(); for (name, tool) in tools { // Skip invalid tools let Ok(tool) = tool else { @@ -79,14 +75,14 @@ pub(crate) async fn list( if show_paths { writeln!( - printer.stdout(), + buffer, "{} ({})", format!("{name} v{version}{version_specifier}").bold(), installed_tools.tool_dir(&name).simplified_display().cyan(), )?; } else { writeln!( - printer.stdout(), + buffer, "{}", format!("{name} v{version}{version_specifier}").bold() )?; @@ -96,17 +92,26 @@ pub(crate) async fn list( for entrypoint in tool.entrypoints() { if show_paths { writeln!( - printer.stdout(), + buffer, "- {} ({})", entrypoint.name, entrypoint.install_path.simplified_display().cyan() )?; } else { - writeln!(printer.stdout(), "- {}", entrypoint.name)?; + writeln!(buffer, "- {}", entrypoint.name)?; } } } - writeln!(printer.stdout(), "\nSee `uvx --help` for more information.")?; + if buffer.is_empty() { + writeln!(printer.stderr(), "{no_tools_installed_msg}")?; + return Ok(ExitStatus::Success); + } + + writeln!( + printer.stdout(), + "The following tools are already installed:\n" + )?; + writeln!(printer.stdout(), "{buffer}")?; Ok(ExitStatus::Success) } diff --git a/crates/uv/src/commands/tool/run.rs b/crates/uv/src/commands/tool/run.rs index 1a120f633abc..dba10b1e1645 100644 --- a/crates/uv/src/commands/tool/run.rs +++ b/crates/uv/src/commands/tool/run.rs @@ -81,7 +81,17 @@ pub(crate) async fn run( ) -> anyhow::Result { // treat empty command as `uv tool list` let Some(command) = command else { - return tool_list(false, false, &cache, printer).await; + writeln!( + printer.stdout(), + "Provide a command to invoke with `{invocation_source} ` \ + or `{invocation_source} --from `.\n" + )?; + let result = tool_list(false, false, &cache, printer).await; + writeln!( + printer.stdout(), + "See `{invocation_source} --help` for more information." + )?; + return result; }; let (target, args) = command.split(); diff --git a/crates/uv/tests/tool_list.rs b/crates/uv/tests/tool_list.rs index ac4f427009b0..379377a19948 100644 --- a/crates/uv/tests/tool_list.rs +++ b/crates/uv/tests/tool_list.rs @@ -30,15 +30,12 @@ fn tool_list() { success: true exit_code: 0 ----- stdout ----- - Provide a command to invoke with `uvx ` or `uvx --from `. - The following tools are already installed: black v24.2.0 - black - blackd - See `uvx --help` for more information. ----- stderr ----- "###); @@ -65,15 +62,12 @@ fn tool_list_paths() { success: true exit_code: 0 ----- stdout ----- - Provide a command to invoke with `uvx ` or `uvx --from `. - The following tools are already installed: black v24.2.0 ([TEMP_DIR]/tools/black) - black ([TEMP_DIR]/bin/black) - blackd ([TEMP_DIR]/bin/blackd) - See `uvx --help` for more information. ----- stderr ----- "###); @@ -122,15 +116,12 @@ fn tool_list_missing_receipt() { success: true exit_code: 0 ----- stdout ----- - Provide a command to invoke with `uvx ` or `uvx --from `. - - The following tools are already installed: - - - See `uvx --help` for more information. ----- stderr ----- warning: Ignoring malformed tool `black` (run `uv tool uninstall black` to remove) + No tools installed. + + See `uv tool install --help` for more information. "###); } @@ -175,14 +166,11 @@ fn tool_list_bad_environment() -> Result<()> { success: true exit_code: 0 ----- stdout ----- - Provide a command to invoke with `uvx ` or `uvx --from `. - The following tools are already installed: ruff v0.3.4 - ruff - See `uvx --help` for more information. ----- stderr ----- Invalid environment at `tools/black`: missing Python executable at `tools/black/[BIN]/python` @@ -244,15 +232,12 @@ fn tool_list_deprecated() -> Result<()> { success: true exit_code: 0 ----- stdout ----- - Provide a command to invoke with `uvx ` or `uvx --from `. - The following tools are already installed: black v24.2.0 - black - blackd - See `uvx --help` for more information. ----- stderr ----- "###); @@ -277,15 +262,12 @@ fn tool_list_deprecated() -> Result<()> { success: true exit_code: 0 ----- stdout ----- - Provide a command to invoke with `uvx ` or `uvx --from `. - - The following tools are already installed: - - - See `uvx --help` for more information. ----- stderr ----- warning: Ignoring malformed tool `black` (run `uv tool uninstall black` to remove) + No tools installed. + + See `uv tool install --help` for more information. "###); Ok(()) @@ -312,15 +294,12 @@ fn tool_list_show_version_specifiers() { success: true exit_code: 0 ----- stdout ----- - Provide a command to invoke with `uvx ` or `uvx --from `. - The following tools are already installed: black v24.2.0 [required: <24.3.0] - black - blackd - See `uvx --help` for more information. ----- stderr ----- "###); diff --git a/crates/uv/tests/tool_run.rs b/crates/uv/tests/tool_run.rs index 07f089859ff2..c17be88a688b 100644 --- a/crates/uv/tests/tool_run.rs +++ b/crates/uv/tests/tool_run.rs @@ -753,6 +753,10 @@ fn tool_run_list_installed() { success: true exit_code: 0 ----- stdout ----- + Provide a command to invoke with `uv tool run ` or `uv tool run --from `. + + + See `uv tool run --help` for more information. ----- stderr ----- No tools installed.