Refactor `uv tool run` hint into separate function (#11069)

This commit is contained in:
Zanie Blue 2025-01-29 11:55:54 -06:00 committed by GitHub
parent 3af3af5039
commit d866c58ea2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 63 additions and 41 deletions

View File

@ -193,47 +193,14 @@ pub(crate) async fn run(
let handle = match process.spawn() {
Ok(handle) => Ok(handle),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
match get_entrypoints(&from.name, &site_packages) {
Ok(entrypoints) => {
writeln!(
printer.stdout(),
"The executable `{}` was not found.",
executable.cyan(),
)?;
if entrypoints.is_empty() {
warn_user!(
"Package `{}` does not provide any executables.",
from.name.red()
);
} else {
warn_user!(
"An executable named `{}` is not provided by package `{}`.",
executable.cyan(),
from.name.red()
);
writeln!(
printer.stdout(),
"The following executables are provided by `{}`:",
from.name.green()
)?;
for (name, _) in entrypoints {
writeln!(printer.stdout(), "- {}", name.cyan())?;
}
let suggested_command = format!(
"{} --from {} <EXECUTABLE_NAME>",
invocation_source, from.name
);
writeln!(
printer.stdout(),
"Consider using `{}` instead.",
suggested_command.green()
)?;
}
return Ok(ExitStatus::Failure);
}
Err(err) => {
warn!("Failed to get entrypoints for `{from}`: {err}");
}
if let Some(exit_status) = hint_on_not_found(
executable,
&from,
&site_packages,
invocation_source,
printer,
)? {
return Ok(exit_status);
}
Err(err)
}
@ -244,6 +211,61 @@ pub(crate) async fn run(
run_to_completion(handle).await
}
/// Show a hint when a command fails due to a missing executable.
///
/// Returns an exit status if the caller should exit after hinting.
fn hint_on_not_found(
executable: &str,
from: &Requirement,
site_packages: &SitePackages,
invocation_source: ToolRunCommand,
printer: Printer,
) -> anyhow::Result<Option<ExitStatus>> {
match get_entrypoints(&from.name, site_packages) {
Ok(entrypoints) => {
writeln!(
printer.stdout(),
"The executable `{}` was not found.",
executable.cyan(),
)?;
if entrypoints.is_empty() {
warn_user!(
"Package `{}` does not provide any executables.",
from.name.red()
);
} else {
warn_user!(
"An executable named `{}` is not provided by package `{}`.",
executable.cyan(),
from.name.red()
);
writeln!(
printer.stdout(),
"The following executables are provided by `{}`:",
from.name.green()
)?;
for (name, _) in entrypoints {
writeln!(printer.stdout(), "- {}", name.cyan())?;
}
let suggested_command = format!(
"{} --from {} <EXECUTABLE_NAME>",
invocation_source, from.name
);
writeln!(
printer.stdout(),
"Consider using `{}` instead.",
suggested_command.green()
)?;
}
Ok(Some(ExitStatus::Failure))
}
Err(err) => {
warn!("Failed to get entrypoints for `{from}`: {err}");
Ok(None)
}
}
}
/// Return the entry points for the specified package.
fn get_entrypoints(
from: &PackageName,