uv tool run error messages references uvx when appropriate (#5014)

## Summary

Resolves #5013. 

## Test Plan

```console
❯ ./target/debug/uv tool run fastapi-cli
warning: `uv tool run` is experimental and may change without warning.
Resolved 9 packages in 28ms
The executable fastapi-cli was not found.
However, the following executables are available via uv tool run --from fastapi-cli <EXECUTABLE>:
- fastapi
```

```console
❯ ./target/debug/uvx fastapi-cli
warning: `uvx` is experimental and may change without warning.
Resolved 9 packages in 23ms
The executable fastapi-cli was not found.
However, the following executables are available via uvx --from fastapi-cli <EXECUTABLE>:
- fastapi
```

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
Ahmed Ilyas 2024-07-12 19:17:26 +02:00 committed by GitHub
parent 2ccb7ed305
commit 26d8879c3a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 32 additions and 6 deletions

View file

@ -36,6 +36,7 @@ pub(crate) use tool::dir::dir as tool_dir;
pub(crate) use tool::install::install as tool_install; pub(crate) use tool::install::install as tool_install;
pub(crate) use tool::list::list as tool_list; pub(crate) use tool::list::list as tool_list;
pub(crate) use tool::run::run as tool_run; pub(crate) use tool::run::run as tool_run;
pub(crate) use tool::run::ToolRunCommand;
pub(crate) use tool::uninstall::uninstall as tool_uninstall; pub(crate) use tool::uninstall::uninstall as tool_uninstall;
use uv_cache::Cache; use uv_cache::Cache;
use uv_fs::Simplified; use uv_fs::Simplified;

View file

@ -1,8 +1,8 @@
use std::borrow::Cow;
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt::Write; use std::fmt::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::{borrow::Cow, fmt::Display};
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use itertools::Itertools; use itertools::Itertools;
@ -32,6 +32,23 @@ use crate::commands::{ExitStatus, SharedState};
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::ResolverInstallerSettings; use crate::settings::ResolverInstallerSettings;
/// The user-facing command used to invoke a tool run.
pub(crate) enum ToolRunCommand {
/// via the `uvx` alias
Uvx,
/// via `uv tool run`
ToolRun,
}
impl Display for ToolRunCommand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ToolRunCommand::Uvx => write!(f, "uvx"),
ToolRunCommand::ToolRun => write!(f, "uv tool run"),
}
}
}
/// Run a command. /// Run a command.
pub(crate) async fn run( pub(crate) async fn run(
command: ExternalCommand, command: ExternalCommand,
@ -39,6 +56,7 @@ pub(crate) async fn run(
with: Vec<String>, with: Vec<String>,
python: Option<String>, python: Option<String>,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
invocation_source: ToolRunCommand,
isolated: bool, isolated: bool,
preview: PreviewMode, preview: PreviewMode,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -50,7 +68,7 @@ pub(crate) async fn run(
printer: Printer, printer: Printer,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
if preview.is_disabled() { if preview.is_disabled() {
warn_user_once!("`uv tool run` is experimental and may change without warning."); warn_user_once!("`{invocation_source}` is experimental and may change without warning.");
} }
let has_from = from.is_some(); let has_from = from.is_some();
@ -144,7 +162,7 @@ pub(crate) async fn run(
"However, the following executables are available:", "However, the following executables are available:",
)?; )?;
} else { } else {
let command = format!("uv tool run --from {from} <EXECUTABLE>"); let command = format!("{invocation_source} --from {from} <EXECUTABLE>");
writeln!( writeln!(
printer.stdout(), printer.stdout(),
"However, the following executables are available via {}:", "However, the following executables are available via {}:",

View file

@ -26,7 +26,7 @@ use uv_distribution::Workspace;
use uv_requirements::RequirementsSource; use uv_requirements::RequirementsSource;
use uv_settings::{Combine, FilesystemOptions}; use uv_settings::{Combine, FilesystemOptions};
use crate::commands::ExitStatus; use crate::commands::{ExitStatus, ToolRunCommand};
use crate::printer::Printer; use crate::printer::Printer;
use crate::settings::{ use crate::settings::{
CacheSettings, GlobalSettings, PipCheckSettings, PipCompileSettings, PipFreezeSettings, CacheSettings, GlobalSettings, PipCheckSettings, PipCompileSettings, PipFreezeSettings,
@ -598,21 +598,28 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
Ok(ExitStatus::Success) Ok(ExitStatus::Success)
} }
Commands::Tool(ToolNamespace { Commands::Tool(ToolNamespace {
command: ToolCommand::Run(args) | ToolCommand::Uvx(args), command: run_variant @ (ToolCommand::Uvx(_) | ToolCommand::Run(_)),
}) => { }) => {
let (args, invocation_source) = match run_variant {
ToolCommand::Uvx(args) => (args, ToolRunCommand::Uvx),
ToolCommand::Run(args) => (args, ToolRunCommand::ToolRun),
// OK guarded by the outer match statement
_ => unreachable!(),
};
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::ToolRunSettings::resolve(args, filesystem); let args = settings::ToolRunSettings::resolve(args, filesystem);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
let cache = cache.init()?.with_refresh(args.refresh); let cache = cache.init()?.with_refresh(args.refresh);
commands::tool_run( commands::tool_run(
args.command, args.command,
args.from, args.from,
args.with, args.with,
args.python, args.python,
args.settings, args.settings,
invocation_source,
globals.isolated, globals.isolated,
globals.preview, globals.preview,
globals.python_preference, globals.python_preference,