diff --git a/crates/uv/src/commands/mod.rs b/crates/uv/src/commands/mod.rs index 517a7d27da9c..3ba1b75baa9d 100644 --- a/crates/uv/src/commands/mod.rs +++ b/crates/uv/src/commands/mod.rs @@ -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::list::list as tool_list; pub(crate) use tool::run::run as tool_run; +pub(crate) use tool::run::ToolRunCommand; pub(crate) use tool::uninstall::uninstall as tool_uninstall; use uv_cache::Cache; use uv_fs::Simplified; diff --git a/crates/uv/src/commands/tool/run.rs b/crates/uv/src/commands/tool/run.rs index c24a35022748..c402cba33b12 100644 --- a/crates/uv/src/commands/tool/run.rs +++ b/crates/uv/src/commands/tool/run.rs @@ -1,8 +1,8 @@ -use std::borrow::Cow; use std::ffi::OsString; use std::fmt::Write; use std::path::PathBuf; use std::str::FromStr; +use std::{borrow::Cow, fmt::Display}; use anyhow::{bail, Context, Result}; use itertools::Itertools; @@ -32,6 +32,23 @@ use crate::commands::{ExitStatus, SharedState}; use crate::printer::Printer; 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. pub(crate) async fn run( command: ExternalCommand, @@ -39,6 +56,7 @@ pub(crate) async fn run( with: Vec, python: Option, settings: ResolverInstallerSettings, + invocation_source: ToolRunCommand, isolated: bool, preview: PreviewMode, python_preference: PythonPreference, @@ -50,7 +68,7 @@ pub(crate) async fn run( printer: Printer, ) -> Result { 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(); @@ -144,7 +162,7 @@ pub(crate) async fn run( "However, the following executables are available:", )?; } else { - let command = format!("uv tool run --from {from} "); + let command = format!("{invocation_source} --from {from} "); writeln!( printer.stdout(), "However, the following executables are available via {}:", diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 971396843ac6..82136317f4d8 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -26,7 +26,7 @@ use uv_distribution::Workspace; use uv_requirements::RequirementsSource; use uv_settings::{Combine, FilesystemOptions}; -use crate::commands::ExitStatus; +use crate::commands::{ExitStatus, ToolRunCommand}; use crate::printer::Printer; use crate::settings::{ CacheSettings, GlobalSettings, PipCheckSettings, PipCompileSettings, PipFreezeSettings, @@ -598,21 +598,28 @@ async fn run(cli: Cli) -> Result { Ok(ExitStatus::Success) } 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. let args = settings::ToolRunSettings::resolve(args, filesystem); show_settings!(args); // Initialize the cache. let cache = cache.init()?.with_refresh(args.refresh); - commands::tool_run( args.command, args.from, args.with, args.python, args.settings, + invocation_source, globals.isolated, globals.preview, globals.python_preference,