mirror of https://github.com/astral-sh/uv
Add hint for misplaced `--verbose` in `uv tool run` (#17020)
Resolves #16777 ## Summary When a command fails, users sometimes add --verbose after the package name (e.g., uvx foo --verbose) instead of before it (e.g., uvx --verbose foo). This adds a hint that suggests moving --verbose before the command. The hint appears when a verbose flag is detected in the subcommand arguments and the command fails to resolve. It works for both uvx and uv tool run. ## Test Plan Tested by running: uvx foo-does-not-exist --verbose - shows the hint uv tool run foo-does-not-exist --verbose - shows the hint The hint only appears when verbose flags are detected, and the message shows the correct command format. ## Screenshot <img width="920" height="34" alt="image" src="https://github.com/user-attachments/assets/f6c303f6-b5e6-441f-8d8d-9f5e6ab87c87" /> Open to feedback and happy to make changes as needed! 💯 --------- Co-authored-by: Tomasz (Tom) Kramkowski <tom@astral.sh>
This commit is contained in:
parent
a70ee58ae1
commit
38ce3b2919
|
|
@ -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(
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -2820,6 +2820,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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue