Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions crates/uv/src/commands/tool/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ impl Display for ToolRunCommand {
}
}

/// Check if the given arguments contain a verbose flag (e.g., `--verbose`, `-v`, `-vv`, etc.)
fn find_verbose_flag(args: &[std::ffi::OsString]) -> Option<&str> {
args.iter().find_map(|arg| {
let arg_str = arg.to_str()?;
if arg_str == "--verbose" {
Some("--verbose")
} else if arg_str.starts_with("-v") && arg_str.chars().skip(1).all(|c| c == 'v') {
Some(arg_str)
} else {
None
}
})
}

/// Run a command.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn run(
Expand Down Expand Up @@ -309,11 +323,24 @@ pub(crate) async fn run(
.map_or(Ok(ExitStatus::Failure), |err| Err(err.into()));
}

return diagnostics::OperationDiagnostic::native_tls(client_builder.is_native_tls())
.with_context("tool")
let diagnostic =
diagnostics::OperationDiagnostic::native_tls(client_builder.is_native_tls());
let diagnostic = if let Some(verbose_flag) = find_verbose_flag(args) {
diagnostic.with_hint(format!(
"You provided `{}` to `{}`. Did you mean to provide it to `{}`? e.g., `{}`",
verbose_flag.cyan(),
target.cyan(),
invocation_source.to_string().cyan(),
format!("{invocation_source} {verbose_flag} {target}").green()
))
} else {
diagnostic.with_context("tool")
};
return diagnostic
.report(err)
.map_or(Ok(ExitStatus::Failure), |err| Err(err.into()));
}

Err(ProjectError::Requirements(err)) => {
let err = miette::Report::msg(format!("{err}"))
.context("Failed to resolve `--with` requirement");
Expand Down
72 changes: 72 additions & 0 deletions crates/uv/tests/it/tool_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2832,6 +2832,78 @@ fn tool_run_with_script_and_from_script() {
");
}

/// Test that when a user provides `--verbose` to the subcommand,
/// we show a helpful hint.
#[test]
fn tool_run_verbose_hint() {
let context = TestContext::new("3.12").with_filtered_counts();
let tool_dir = context.temp_dir.child("tools");
let bin_dir = context.temp_dir.child("bin");

// Test with --verbose flag
uv_snapshot!(context.filters(), context.tool_run()
.arg("nonexistent-package-foo")
.arg("--verbose")
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
success: false
exit_code: 1
----- stdout -----

----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because nonexistent-package-foo was not found in the package registry and you require nonexistent-package-foo, we can conclude that your requirements are unsatisfiable.
help: You provided `--verbose` to `nonexistent-package-foo`. Did you mean to provide it to `uv tool run`? e.g., `uv tool run --verbose nonexistent-package-foo`
"###);

// Test with -v flag
uv_snapshot!(context.filters(), context.tool_run()
.arg("nonexistent-package-bar")
.arg("-v")
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
success: false
exit_code: 1
----- stdout -----

----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because nonexistent-package-bar was not found in the package registry and you require nonexistent-package-bar, we can conclude that your requirements are unsatisfiable.
help: You provided `-v` to `nonexistent-package-bar`. Did you mean to provide it to `uv tool run`? e.g., `uv tool run -v nonexistent-package-bar`
"###);

// Test with -vv flag
uv_snapshot!(context.filters(), context.tool_run()
.arg("nonexistent-package-baz")
.arg("-vv")
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
success: false
exit_code: 1
----- stdout -----

----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because nonexistent-package-baz was not found in the package registry and you require nonexistent-package-baz, we can conclude that your requirements are unsatisfiable.
help: You provided `-vv` to `nonexistent-package-baz`. Did you mean to provide it to `uv tool run`? e.g., `uv tool run -vv nonexistent-package-baz`
"###);

// Test for false positives
uv_snapshot!(context.filters(), context.tool_run()
.arg("nonexistent-package-quux")
.arg("-version")
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r"
success: false
exit_code: 1
----- stdout -----

----- stderr -----
× No solution found when resolving tool dependencies:
╰─▶ Because nonexistent-package-quux was not found in the package registry and you require nonexistent-package-quux, we can conclude that your requirements are unsatisfiable.
");
}

#[test]
fn tool_run_with_compatible_build_constraints() -> Result<()> {
let context = TestContext::new("3.9")
Expand Down
Loading