From 439fe6c7c36750a13a9a07f961de1e1113cbe6f2 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 29 Jul 2024 19:57:29 -0400 Subject: [PATCH] Suppress resolver output by default in uv run --- crates/uv-cli/src/lib.rs | 8 +++ crates/uv/src/commands/project/run.rs | 13 ++-- crates/uv/src/commands/tool/run.rs | 7 ++- crates/uv/src/lib.rs | 2 + crates/uv/src/printer.rs | 10 +++ crates/uv/src/settings.rs | 10 ++- crates/uv/tests/common/mod.rs | 14 ++--- crates/uv/tests/run.rs | 88 +++++++++++++++++++-------- crates/uv/tests/tool_run.rs | 79 ++++++++++++++++++++---- 9 files changed, 175 insertions(+), 56 deletions(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 2553205039b0f..3dd5d3dd02360 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -1898,6 +1898,10 @@ pub struct RunArgs { #[arg(long, value_parser = parse_maybe_file_path)] pub with_requirements: Vec>, + /// Whether to show resolver and installer output from any environment modifications. + #[arg(long)] + pub show_environment: bool, + /// Assert that the `uv.lock` will remain unchanged. #[arg(long, conflicts_with = "frozen")] pub locked: bool, @@ -2283,6 +2287,10 @@ pub struct ToolRunArgs { #[arg(long, value_parser = parse_maybe_file_path)] pub with_requirements: Vec>, + /// Whether to show resolver and installer output from any environment modifications. + #[arg(long)] + pub show_environment: bool, + #[command(flatten)] pub installer: ResolverInstallerArgs, diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index bcdc1ae74fca1..414c265a15de0 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -38,6 +38,7 @@ use crate::settings::ResolverInstallerSettings; pub(crate) async fn run( command: ExternalCommand, requirements: Vec, + show_environment: bool, locked: bool, frozen: bool, package: Option, @@ -88,7 +89,7 @@ pub(crate) async fn run( // Initialize any shared state. let state = SharedState::default(); - let reporter = PythonDownloadReporter::single(printer); + let reporter = PythonDownloadReporter::single(printer.filter(show_environment)); let directory = if let Some(directory) = directory { directory.simple_canonicalize()? @@ -151,7 +152,7 @@ pub(crate) async fn run( concurrency, native_tls, cache, - printer, + printer.filter(show_environment), ) .await?; @@ -209,7 +210,7 @@ pub(crate) async fn run( connectivity, native_tls, cache, - printer, + printer.filter(show_environment), ) .await?; @@ -225,7 +226,7 @@ pub(crate) async fn run( concurrency, native_tls, cache, - printer, + printer.filter(show_environment), ) .await { @@ -254,7 +255,7 @@ pub(crate) async fn run( concurrency, native_tls, cache, - printer, + printer.filter(show_environment), ) .await?; @@ -410,7 +411,7 @@ pub(crate) async fn run( concurrency, native_tls, cache, - printer, + printer.filter(show_environment), ) .await?, ) diff --git a/crates/uv/src/commands/tool/run.rs b/crates/uv/src/commands/tool/run.rs index efc4a7eae5904..1280f94f0fd8b 100644 --- a/crates/uv/src/commands/tool/run.rs +++ b/crates/uv/src/commands/tool/run.rs @@ -31,7 +31,7 @@ use crate::commands::reporters::PythonDownloadReporter; use crate::commands::project::resolve_names; use crate::commands::{ - project, project::environment::CachedEnvironment, tool::common::matching_packages, tool_list, + project::environment::CachedEnvironment, tool::common::matching_packages, tool_list, }; use crate::commands::{ExitStatus, SharedState}; use crate::printer::Printer; @@ -59,6 +59,7 @@ pub(crate) async fn run( command: Option, from: Option, with: &[RequirementsSource], + show_environment: bool, python: Option, settings: ResolverInstallerSettings, invocation_source: ToolRunCommand, @@ -106,7 +107,7 @@ pub(crate) async fn run( concurrency, native_tls, cache, - printer, + printer.filter(show_environment), ) .await?; @@ -315,7 +316,7 @@ async fn get_or_create_environment( // Resolve the `from` requirement. let from = { - project::resolve_names( + resolve_names( vec![RequirementsSpecification::parse_package(from)?], &interpreter, settings, diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 8c1956b95d1cf..57002fa8c3793 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -645,6 +645,7 @@ async fn run(cli: Cli) -> Result { args.command, args.from, &requirements, + args.show_environment, args.python, args.settings, invocation_source, @@ -909,6 +910,7 @@ async fn run_project( commands::run( args.command, requirements, + args.show_environment, args.locked, args.frozen, args.package, diff --git a/crates/uv/src/printer.rs b/crates/uv/src/printer.rs index 3cd0385153953..cf559eb0b6cef 100644 --- a/crates/uv/src/printer.rs +++ b/crates/uv/src/printer.rs @@ -45,6 +45,16 @@ impl Printer { Self::NoProgress => Stderr::Enabled, } } + + /// Filter the [`Printer`], casting to [`Printer::Quiet`] if the condition is false. + #[must_use] + pub(crate) fn filter(self, condition: bool) -> Self { + if condition { + self + } else { + Self::Quiet + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index f6e014cdb59d2..3410c71b7236c 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -191,6 +191,7 @@ pub(crate) struct RunSettings { pub(crate) command: ExternalCommand, pub(crate) with: Vec, pub(crate) with_requirements: Vec, + pub(crate) show_environment: bool, pub(crate) package: Option, pub(crate) python: Option, pub(crate) directory: Option, @@ -203,8 +204,6 @@ impl RunSettings { #[allow(clippy::needless_pass_by_value)] pub(crate) fn resolve(args: RunArgs, filesystem: Option) -> Self { let RunArgs { - locked, - frozen, extra, all_extras, no_all_extras, @@ -213,6 +212,9 @@ impl RunSettings { command, with, with_requirements, + show_environment, + locked, + frozen, installer, build, refresh, @@ -235,6 +237,7 @@ impl RunSettings { .into_iter() .filter_map(Maybe::into_option) .collect(), + show_environment, package, python, directory, @@ -255,6 +258,7 @@ pub(crate) struct ToolRunSettings { pub(crate) from: Option, pub(crate) with: Vec, pub(crate) with_requirements: Vec, + pub(crate) show_environment: bool, pub(crate) python: Option, pub(crate) refresh: Refresh, pub(crate) settings: ResolverInstallerSettings, @@ -269,6 +273,7 @@ impl ToolRunSettings { from, with, with_requirements, + show_environment, installer, build, refresh, @@ -283,6 +288,7 @@ impl ToolRunSettings { .into_iter() .filter_map(Maybe::into_option) .collect(), + show_environment, python, refresh: Refresh::from(refresh), settings: ResolverInstallerSettings::combine( diff --git a/crates/uv/tests/common/mod.rs b/crates/uv/tests/common/mod.rs index 767692505a88b..6128c9b654535 100644 --- a/crates/uv/tests/common/mod.rs +++ b/crates/uv/tests/common/mod.rs @@ -495,7 +495,7 @@ impl TestContext { } /// Create a `uv tool install` command with options shared across scenarios. - pub fn tool_install(&self) -> std::process::Command { + pub fn tool_install(&self) -> Command { let mut command = self.tool_install_without_exclude_newer(); command.arg("--exclude-newer").arg(EXCLUDE_NEWER); command @@ -507,16 +507,16 @@ impl TestContext { /// it can result in tests failing when the index state changes. Therefore, /// if you use this, there should be some other kind of mitigation in place. /// For example, pinning package versions. - pub fn tool_install_without_exclude_newer(&self) -> std::process::Command { - let mut command = std::process::Command::new(get_bin()); + pub fn tool_install_without_exclude_newer(&self) -> Command { + let mut command = Command::new(get_bin()); command.arg("tool").arg("install"); self.add_shared_args(&mut command); command } /// Create a `uv tool list` command with options shared across scenarios. - pub fn tool_list(&self) -> std::process::Command { - let mut command = std::process::Command::new(get_bin()); + pub fn tool_list(&self) -> Command { + let mut command = Command::new(get_bin()); command.arg("tool").arg("list"); self.add_shared_args(&mut command); command @@ -531,8 +531,8 @@ impl TestContext { } /// Create a `uv tool uninstall` command with options shared across scenarios. - pub fn tool_uninstall(&self) -> std::process::Command { - let mut command = std::process::Command::new(get_bin()); + pub fn tool_uninstall(&self) -> Command { + let mut command = Command::new(get_bin()); command.arg("tool").arg("uninstall"); self.add_shared_args(&mut command); command diff --git a/crates/uv/tests/run.rs b/crates/uv/tests/run.rs index 0c11785a18a10..c8dc5b424233c 100644 --- a/crates/uv/tests/run.rs +++ b/crates/uv/tests/run.rs @@ -42,6 +42,7 @@ fn run_with_python_version() -> Result<()> { // get stale files, see https://github.com/python/cpython/issues/75953. let mut command = context.run(); let command_with_args = command + .arg("--show-environment") .arg("--preview") .arg("python") .arg("-B") @@ -68,6 +69,7 @@ fn run_with_python_version() -> Result<()> { // This is the same Python, no reinstallation. let mut command = context.run(); let command_with_args = command + .arg("--show-environment") .arg("--preview") .arg("-p") .arg("3.12") @@ -89,6 +91,7 @@ fn run_with_python_version() -> Result<()> { // This time, we target Python 3.11 instead. let mut command = context.run(); let command_with_args = command + .arg("--show-environment") .arg("--preview") .arg("-p") .arg("3.11") @@ -120,6 +123,7 @@ fn run_with_python_version() -> Result<()> { // This time, we target Python 3.8 instead. let mut command = context.run(); let command_with_args = command + .arg("--show-environment") .arg("--preview") .arg("-p") .arg("3.8") @@ -156,7 +160,7 @@ fn run_args() -> Result<()> { })?; // We treat arguments before the command as uv arguments - uv_snapshot!(context.filters(), context.run().arg("--version").arg("python"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--version").arg("python"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -166,7 +170,7 @@ fn run_args() -> Result<()> { "###); // We don't treat arguments after the command as uv arguments - uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("python").arg("--version"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -181,7 +185,7 @@ fn run_args() -> Result<()> { "###); // Can use `--` to separate uv arguments from the command arguments. - uv_snapshot!(context.filters(), context.run().arg("--").arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--").arg("python").arg("--version"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -227,7 +231,7 @@ fn run_script() -> Result<()> { })?; // Running the script should install the requirements. - uv_snapshot!(context.filters(), context.run().arg("--preview").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--preview").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -241,7 +245,7 @@ fn run_script() -> Result<()> { "###); // Running again should use the existing environment. - uv_snapshot!(context.filters(), context.run().arg("--preview").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--preview").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -259,7 +263,7 @@ fn run_script() -> Result<()> { " })?; - uv_snapshot!(context.filters(), context.run().arg("--preview").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--preview").arg("main.py"), @r###" success: false exit_code: 1 ----- stdout ----- @@ -287,7 +291,7 @@ fn run_script() -> Result<()> { "# })?; - uv_snapshot!(context.filters(), context.run().arg("--preview").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--preview").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -319,7 +323,7 @@ fn run_managed_false() -> Result<()> { "# })?; - uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("python").arg("--version"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -353,7 +357,7 @@ fn run_with() -> Result<()> { })?; // Requesting an unsatisfied requirement should install it. - uv_snapshot!(context.filters(), context.run().arg("--with").arg("iniconfig").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with").arg("iniconfig").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -374,7 +378,7 @@ fn run_with() -> Result<()> { "###); // Requesting a satisfied requirement should use the base environment. - uv_snapshot!(context.filters(), context.run().arg("--with").arg("sniffio").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with").arg("sniffio").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -386,7 +390,7 @@ fn run_with() -> Result<()> { "###); // Unless the user requests a different version. - uv_snapshot!(context.filters(), context.run().arg("--with").arg("sniffio<1.3.1").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with").arg("sniffio<1.3.1").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -420,7 +424,7 @@ fn run_locked() -> Result<()> { )?; // Running with `--locked` should error, if no lockfile is present. - uv_snapshot!(context.filters(), context.run().arg("--locked").arg("--").arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--locked").arg("--").arg("python").arg("--version"), @r###" success: false exit_code: 2 ----- stdout ----- @@ -447,7 +451,7 @@ fn run_locked() -> Result<()> { )?; // Running with `--locked` should error. - uv_snapshot!(context.filters(), context.run().arg("--locked").arg("--").arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--locked").arg("--").arg("python").arg("--version"), @r###" success: false exit_code: 2 ----- stdout ----- @@ -467,7 +471,7 @@ fn run_locked() -> Result<()> { context.lock().assert().success(); // Running with `--locked` should succeed. - uv_snapshot!(context.filters(), context.run().arg("--locked").arg("--").arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--locked").arg("--").arg("python").arg("--version"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -501,7 +505,7 @@ fn run_frozen() -> Result<()> { )?; // Running with `--frozen` should error, if no lockfile is present. - uv_snapshot!(context.filters(), context.run().arg("--frozen").arg("--").arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--frozen").arg("--").arg("python").arg("--version"), @r###" success: false exit_code: 2 ----- stdout ----- @@ -525,7 +529,7 @@ fn run_frozen() -> Result<()> { )?; // Running with `--frozen` should install the stale lockfile. - uv_snapshot!(context.filters(), context.run().arg("--frozen").arg("--").arg("python").arg("--version"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--frozen").arg("--").arg("python").arg("--version"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -569,7 +573,7 @@ fn run_empty_requirements_txt() -> Result<()> { requirements_txt.touch()?; // The project environment is synced on the first invocation. - uv_snapshot!(context.filters(), context.run().arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -587,7 +591,7 @@ fn run_empty_requirements_txt() -> Result<()> { "###); // Then reused in subsequent invocations - uv_snapshot!(context.filters(), context.run().arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -626,7 +630,7 @@ fn run_requirements_txt() -> Result<()> { let requirements_txt = context.temp_dir.child("requirements.txt"); requirements_txt.write_str("iniconfig")?; - uv_snapshot!(context.filters(), context.run().arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -649,7 +653,7 @@ fn run_requirements_txt() -> Result<()> { // Requesting a satisfied requirement should use the base environment. requirements_txt.write_str("sniffio")?; - uv_snapshot!(context.filters(), context.run().arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -663,7 +667,7 @@ fn run_requirements_txt() -> Result<()> { // Unless the user requests a different version. requirements_txt.write_str("sniffio<1.3.1")?; - uv_snapshot!(context.filters(), context.run().arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -681,7 +685,7 @@ fn run_requirements_txt() -> Result<()> { // Or includes an unsatisfied requirement via `--with`. requirements_txt.write_str("sniffio")?; - uv_snapshot!(context.filters(), context.run() + uv_snapshot!(context.filters(), context.run().arg("--show-environment") .arg("--with-requirements") .arg(requirements_txt.as_os_str()) .arg("--with") @@ -703,7 +707,7 @@ fn run_requirements_txt() -> Result<()> { "###); // But reject `-` as a requirements file. - uv_snapshot!(context.filters(), context.run() + uv_snapshot!(context.filters(), context.run().arg("--show-environment") .arg("--with-requirements") .arg("-") .arg("--with") @@ -750,7 +754,7 @@ fn run_requirements_txt_arguments() -> Result<()> { " })?; - uv_snapshot!(context.filters(), context.run().arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with-requirements").arg(requirements_txt.as_os_str()).arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -805,7 +809,7 @@ fn run_editable() -> Result<()> { })?; // We treat arguments before the command as uv arguments - uv_snapshot!(context.filters(), context.run().arg("--with").arg("iniconfig").arg("main.py"), @r###" + uv_snapshot!(context.filters(), context.run().arg("--show-environment").arg("--with").arg("iniconfig").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -860,6 +864,7 @@ fn run_from_directory() -> Result<()> { let mut command = context.run(); let command_with_args = command + .arg("--show-environment") .arg("--preview") .arg("--directory") .arg("project") @@ -884,3 +889,36 @@ fn run_from_directory() -> Result<()> { Ok(()) } + +/// By default, omit resolver and installer output. +#[test] +fn run_without_output() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! { r#" + [project] + name = "foo" + version = "1.0.0" + requires-python = ">=3.8" + dependencies = ["anyio", "sniffio==1.3.1"] + "# + })?; + + let test_script = context.temp_dir.child("main.py"); + test_script.write_str(indoc! { r" + import sniffio + " + })?; + + uv_snapshot!(context.filters(), context.run().arg("--with").arg("iniconfig").arg("main.py"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + warning: `uv run` is experimental and may change without warning + "###); + + Ok(()) +} diff --git a/crates/uv/tests/tool_run.rs b/crates/uv/tests/tool_run.rs index 8bb97fbcfcbb3..f16a5a1756061 100644 --- a/crates/uv/tests/tool_run.rs +++ b/crates/uv/tests/tool_run.rs @@ -15,6 +15,7 @@ fn tool_run_args() { // We treat arguments before the command as uv arguments uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--version") .arg("pytest") .env("UV_TOOL_DIR", tool_dir.as_os_str()) @@ -29,6 +30,7 @@ fn tool_run_args() { // We don't treat arguments after the command as uv arguments uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("pytest") .arg("--version") .env("UV_TOOL_DIR", tool_dir.as_os_str()) @@ -51,6 +53,7 @@ fn tool_run_args() { // Can use `--` to separate uv arguments from the command arguments. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--") .arg("pytest") .arg("--version") @@ -74,6 +77,7 @@ fn tool_run_at_version() { let bin_dir = context.temp_dir.child("bin"); uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("pytest@8.0.0") .arg("--version") .env("UV_TOOL_DIR", tool_dir.as_os_str()) @@ -96,6 +100,7 @@ fn tool_run_at_version() { // Empty versions are just treated as package and command names uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("pytest@") .arg("--version") .env("UV_TOOL_DIR", tool_dir.as_os_str()) @@ -114,6 +119,7 @@ fn tool_run_at_version() { // Invalid versions are just treated as package and command names uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("pytest@invalid") .arg("--version") .env("UV_TOOL_DIR", tool_dir.as_os_str()) @@ -139,12 +145,13 @@ fn tool_run_at_version() { // When `--from` is used, `@` is not treated as a version request uv_snapshot!(filters, context.tool_run() - .arg("--from") - .arg("pytest") - .arg("pytest@8.0.0") - .arg("--version") - .env("UV_TOOL_DIR", tool_dir.as_os_str()) - .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" + .arg("--show-environment") + .arg("--from") + .arg("pytest") + .arg("pytest@8.0.0") + .arg("--version") + .env("UV_TOOL_DIR", tool_dir.as_os_str()) + .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" success: false exit_code: 1 ----- stdout ----- @@ -173,6 +180,7 @@ fn tool_run_from_version() { let bin_dir = context.temp_dir.child("bin"); uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--from") .arg("pytest==8.0.0") .arg("pytest") @@ -203,6 +211,7 @@ fn tool_run_suggest_valid_commands() { let bin_dir = context.temp_dir.child("bin"); uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--from") .arg("black") .arg("orange") @@ -231,6 +240,7 @@ fn tool_run_suggest_valid_commands() { "###); uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("fastapi-cli") .env("UV_TOOL_DIR", tool_dir.as_os_str()) .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" @@ -262,13 +272,14 @@ fn tool_run_warn_executable_not_in_from() { filters.push(("(?s)fastapi` instead.*", "fastapi` instead.")); uv_snapshot!(filters, context.tool_run() - .arg("--from") - .arg("fastapi") - .arg("fastapi") - .env("UV_EXCLUDE_NEWER", "2024-05-04T00:00:00Z") // TODO: Remove this once EXCLUDE_NEWER is bumped past 2024-05-04 - // (FastAPI 0.111 is only available from this date onwards) - .env("UV_TOOL_DIR", tool_dir.as_os_str()) - .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" + .arg("--show-environment") + .arg("--from") + .arg("fastapi") + .arg("fastapi") + .env("UV_EXCLUDE_NEWER", "2024-05-04T00:00:00Z") // TODO: Remove this once EXCLUDE_NEWER is bumped past 2024-05-04 + // (FastAPI 0.111 is only available from this date onwards) + .env("UV_TOOL_DIR", tool_dir.as_os_str()) + .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" success: false exit_code: 1 ----- stdout ----- @@ -325,6 +336,7 @@ fn tool_run_from_install() { // Install `black` at a specific version. context .tool_install() + .arg("--show-environment") .arg("black==24.1.0") .env("UV_TOOL_DIR", tool_dir.as_os_str()) .env("XDG_BIN_HOME", bin_dir.as_os_str()) @@ -333,6 +345,7 @@ fn tool_run_from_install() { // Verify that `tool run black` uses the already-installed version. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("black") .arg("--version") .env("UV_TOOL_DIR", tool_dir.as_os_str()) @@ -349,6 +362,7 @@ fn tool_run_from_install() { // Verify that `--isolated` uses an isolated environment. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--isolated") .arg("black") .arg("--version") @@ -375,6 +389,7 @@ fn tool_run_from_install() { // Verify that `tool run black` at a different version installs the new version. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("black@24.1.1") .arg("--version") .env("UV_TOOL_DIR", tool_dir.as_os_str()) @@ -402,6 +417,7 @@ fn tool_run_from_install() { // TODO(charlie): This could (in theory) layer the `--with` requirements on top of the existing // environment. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--with") .arg("iniconfig") .arg("black") @@ -430,6 +446,7 @@ fn tool_run_from_install() { // Verify that `tool run black` at a different version (via `--from`) installs the new version. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--from") .arg("black==24.2.0") .arg("black") @@ -464,6 +481,7 @@ fn tool_run_cache() { // Verify that `tool run black` installs the latest version. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("-p") .arg("3.12") .arg("black") @@ -491,6 +509,7 @@ fn tool_run_cache() { // Verify that `tool run black` uses the cached version. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("-p") .arg("3.12") .arg("black") @@ -510,6 +529,7 @@ fn tool_run_cache() { // Verify that `--reinstall` reinstalls everything. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("-p") .arg("3.12") .arg("--reinstall") @@ -538,6 +558,7 @@ fn tool_run_cache() { // Verify that `--reinstall-package` reinstalls everything. We may want to change this. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("-p") .arg("3.12") .arg("--reinstall-package") @@ -567,6 +588,7 @@ fn tool_run_cache() { // Verify that varying the interpreter leads to a fresh environment. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("-p") .arg("3.11") .arg("black") @@ -594,6 +616,7 @@ fn tool_run_cache() { // But that re-invoking with the previous interpreter retains the cached version. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("-p") .arg("3.12") .arg("black") @@ -613,6 +636,7 @@ fn tool_run_cache() { // Verify that `--with` leads to a fresh environment. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("-p") .arg("3.12") .arg("--with") @@ -649,6 +673,7 @@ fn tool_run_url() { let bin_dir = context.temp_dir.child("bin"); uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--from") .arg("flask @ https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl") .arg("flask") @@ -688,6 +713,7 @@ fn tool_run_requirements_txt() { requirements_txt.write_str("iniconfig").unwrap(); uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--with-requirements") .arg("requirements.txt") .arg("--with") @@ -737,6 +763,7 @@ fn tool_run_requirements_txt_arguments() { .unwrap(); uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .arg("--with-requirements") .arg("requirements.txt") .arg("flask") @@ -776,6 +803,7 @@ fn tool_run_list_installed() { // No tools installed. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .env("UV_TOOL_DIR", tool_dir.as_os_str()) .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" success: true @@ -798,6 +826,7 @@ fn tool_run_list_installed() { // List installed tools. uv_snapshot!(context.filters(), context.tool_run() + .arg("--show-environment") .env("UV_TOOL_DIR", tool_dir.as_os_str()) .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" success: true @@ -811,3 +840,27 @@ fn tool_run_list_installed() { warning: `uv tool run` is experimental and may change without warning "###); } + +/// By default, omit resolver and installer output. +#[test] +fn tool_run_without_output() { + 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"); + + // Can use `--` to separate uv arguments from the command arguments. + uv_snapshot!(context.filters(), context.tool_run() + .arg("--") + .arg("pytest") + .arg("--version") + .env("UV_TOOL_DIR", tool_dir.as_os_str()) + .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" + success: true + exit_code: 0 + ----- stdout ----- + pytest 8.1.1 + + ----- stderr ----- + warning: `uv tool run` is experimental and may change without warning + "###); +}