Skip to content

Commit

Permalink
Implement --show-version-specifiers for tool list (#7050)
Browse files Browse the repository at this point in the history
## Summary

Closes #6747 .

## Test Plan

```
cargo test --test tool_list
```
  • Loading branch information
eth3lbert authored Sep 5, 2024
1 parent a20fece commit e7a7a81
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 8 deletions.
5 changes: 5 additions & 0 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3165,9 +3165,14 @@ pub struct ToolListArgs {
#[arg(long)]
pub show_paths: bool,

/// Whether to display the version specifier(s) used to install each tool.
#[arg(long)]
pub show_version_specifiers: bool,

// Hide unused global Python options.
#[arg(long, hide = true)]
pub python_preference: Option<PythonPreference>,

#[arg(long, hide = true)]
pub no_python_downloads: bool,
}
Expand Down
31 changes: 27 additions & 4 deletions crates/uv/src/commands/tool/list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::Write;

use anyhow::Result;
use itertools::Itertools;
use owo_colors::OwoColorize;

use uv_cache::Cache;
Expand All @@ -12,7 +13,12 @@ use crate::commands::ExitStatus;
use crate::printer::Printer;

/// List installed tools.
pub(crate) async fn list(show_paths: bool, cache: &Cache, printer: Printer) -> Result<ExitStatus> {
pub(crate) async fn list(
show_paths: bool,
show_version_specifiers: bool,
cache: &Cache,
printer: Printer,
) -> Result<ExitStatus> {
let installed_tools = InstalledTools::from_settings()?;
let _lock = match installed_tools.lock().await {
Ok(lock) => lock,
Expand Down Expand Up @@ -50,15 +56,32 @@ pub(crate) async fn list(show_paths: bool, cache: &Cache, printer: Printer) -> R
}
};

let version_specifier = if show_version_specifiers {
let specifiers = tool
.requirements()
.iter()
.filter(|req| req.name == name)
.map(|req| req.source.to_string())
.filter(|s| !s.is_empty())
.join(", ");
format!(" [required: {specifiers}]")
} else {
String::new()
};

if show_paths {
writeln!(
printer.stdout(),
"{} ({})",
format!("{name} v{version}").bold(),
installed_tools.tool_dir(&name).simplified_display().cyan()
format!("{name} v{version}{version_specifier}").bold(),
installed_tools.tool_dir(&name).simplified_display().cyan(),
)?;
} else {
writeln!(printer.stdout(), "{}", format!("{name} v{version}").bold())?;
writeln!(
printer.stdout(),
"{}",
format!("{name} v{version}{version_specifier}").bold()
)?;
}

// Output tool entrypoints
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/commands/tool/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub(crate) async fn run(
) -> anyhow::Result<ExitStatus> {
// treat empty command as `uv tool list`
let Some(command) = command else {
return tool_list(false, &cache, printer).await;
return tool_list(false, false, &cache, printer).await;
};

let (target, args) = command.split();
Expand Down
8 changes: 7 additions & 1 deletion crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,13 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
// Initialize the cache.
let cache = cache.init()?;

commands::tool_list(args.show_paths, &cache, printer).await
commands::tool_list(
args.show_paths,
args.show_version_specifiers,
&cache,
printer,
)
.await
}
Commands::Tool(ToolNamespace {
command: ToolCommand::Upgrade(args),
Expand Down
13 changes: 11 additions & 2 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,15 +457,24 @@ impl ToolUpgradeSettings {
#[derive(Debug, Clone)]
pub(crate) struct ToolListSettings {
pub(crate) show_paths: bool,
pub(crate) show_version_specifiers: bool,
}

impl ToolListSettings {
/// Resolve the [`ToolListSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: ToolListArgs, _filesystem: Option<FilesystemOptions>) -> Self {
let ToolListArgs { show_paths, .. } = args;
let ToolListArgs {
show_paths,
show_version_specifiers,
python_preference: _,
no_python_downloads: _,
} = args;

Self { show_paths }
Self {
show_paths,
show_version_specifiers,
}
}
}

Expand Down
43 changes: 43 additions & 0 deletions crates/uv/tests/tool_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,46 @@ fn tool_list_deprecated() -> Result<()> {

Ok(())
}

#[test]
fn tool_list_show_version_specifiers() {
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");

// Install `black`
context
.tool_install()
.arg("black<24.3.0")
.env("UV_TOOL_DIR", tool_dir.as_os_str())
.env("XDG_BIN_HOME", bin_dir.as_os_str())
.assert()
.success();

uv_snapshot!(context.filters(), context.tool_list().arg("--show-version-specifiers")
.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 [required: <24.3.0]
- black
- blackd
----- stderr -----
"###);

// with paths
uv_snapshot!(context.filters(), context.tool_list().arg("--show-version-specifiers").arg("--show-paths")
.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 [required: <24.3.0] ([TEMP_DIR]/tools/black)
- black ([TEMP_DIR]/bin/black)
- blackd ([TEMP_DIR]/bin/blackd)
----- stderr -----
"###);
}
2 changes: 2 additions & 0 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -3141,6 +3141,8 @@ uv tool list [OPTIONS]

</dd><dt><code>--show-paths</code></dt><dd><p>Whether to display the path to each tool environment and installed executable</p>

</dd><dt><code>--show-version-specifiers</code></dt><dd><p>Whether to display the version specifier(s) used to install each tool</p>

</dd><dt><code>--verbose</code>, <code>-v</code></dt><dd><p>Use verbose output.</p>

<p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (&lt;https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives&gt;)</p>
Expand Down

0 comments on commit e7a7a81

Please sign in to comment.