From 0efc5d0cabebc38b4ee1966fb1e26c471ee68b29 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 22 May 2024 15:43:20 -0400 Subject: [PATCH] Reuse reporting operation in `venv` (#3755) --- crates/bench/benches/uv.rs | 8 +++-- crates/uv-dispatch/src/lib.rs | 8 ++--- crates/uv-resolver/tests/resolver.rs | 8 +++-- crates/uv-types/src/traits.rs | 6 ++-- crates/uv/src/commands/venv.rs | 49 ++++++++++------------------ 5 files changed, 37 insertions(+), 42 deletions(-) diff --git a/crates/bench/benches/uv.rs b/crates/bench/benches/uv.rs index 05c84fa68..3f6db3384 100644 --- a/crates/bench/benches/uv.rs +++ b/crates/bench/benches/uv.rs @@ -42,7 +42,7 @@ mod resolver { use anyhow::Result; use once_cell::sync::Lazy; - use distribution_types::{IndexLocations, Requirement, Resolution, SourceDist}; + use distribution_types::{CachedDist, IndexLocations, Requirement, Resolution, SourceDist}; use pep508_rs::{MarkerEnvironment, MarkerEnvironmentBuilder}; use platform_tags::{Arch, Os, Platform, Tags}; use uv_cache::Cache; @@ -166,7 +166,11 @@ mod resolver { panic!("benchmarks should not build source distributions") } - async fn install<'a>(&'a self, _: &'a Resolution, _: &'a PythonEnvironment) -> Result<()> { + async fn install<'a>( + &'a self, + _: &'a Resolution, + _: &'a PythonEnvironment, + ) -> Result> { panic!("benchmarks should not build source distributions") } diff --git a/crates/uv-dispatch/src/lib.rs b/crates/uv-dispatch/src/lib.rs index 7304b17fe..a09c43cc6 100644 --- a/crates/uv-dispatch/src/lib.rs +++ b/crates/uv-dispatch/src/lib.rs @@ -12,7 +12,7 @@ use itertools::Itertools; use rustc_hash::FxHashMap; use tracing::{debug, instrument}; -use distribution_types::{IndexLocations, Name, Requirement, Resolution, SourceDist}; +use distribution_types::{CachedDist, IndexLocations, Name, Requirement, Resolution, SourceDist}; use uv_build::{SourceBuild, SourceBuildContext}; use uv_cache::Cache; use uv_client::RegistryClient; @@ -176,7 +176,7 @@ impl<'a> BuildContext for BuildDispatch<'a> { &'data self, resolution: &'data Resolution, venv: &'data PythonEnvironment, - ) -> Result<()> { + ) -> Result> { debug!( "Installing in {} in {}", resolution @@ -213,7 +213,7 @@ impl<'a> BuildContext for BuildDispatch<'a> { // Nothing to do. if remote.is_empty() && cached.is_empty() && reinstalls.is_empty() { debug!("No build requirements to install for build"); - return Ok(()); + return Ok(vec![]); } // Resolve any registry-based requirements. @@ -282,7 +282,7 @@ impl<'a> BuildContext for BuildDispatch<'a> { .context("Failed to install build dependencies")?; } - Ok(()) + Ok(wheels) } #[instrument(skip_all, fields(version_id = version_id, subdirectory = ?subdirectory))] diff --git a/crates/uv-resolver/tests/resolver.rs b/crates/uv-resolver/tests/resolver.rs index 196150c86..ec223dd63 100644 --- a/crates/uv-resolver/tests/resolver.rs +++ b/crates/uv-resolver/tests/resolver.rs @@ -10,7 +10,7 @@ use anyhow::Result; use chrono::{DateTime, Utc}; use once_cell::sync::Lazy; -use distribution_types::{IndexLocations, Requirement, Resolution, SourceDist}; +use distribution_types::{CachedDist, IndexLocations, Requirement, Resolution, SourceDist}; use pep508_rs::{MarkerEnvironment, MarkerEnvironmentBuilder}; use platform_tags::{Arch, Os, Platform, Tags}; use uv_cache::Cache; @@ -89,7 +89,11 @@ impl BuildContext for DummyContext { panic!("The test should not need to build source distributions") } - async fn install<'a>(&'a self, _: &'a Resolution, _: &'a PythonEnvironment) -> Result<()> { + async fn install<'a>( + &'a self, + _: &'a Resolution, + _: &'a PythonEnvironment, + ) -> Result> { panic!("The test should not need to build source distributions") } diff --git a/crates/uv-types/src/traits.rs b/crates/uv-types/src/traits.rs index d3c48c915..2f5e91136 100644 --- a/crates/uv-types/src/traits.rs +++ b/crates/uv-types/src/traits.rs @@ -4,7 +4,9 @@ use std::path::{Path, PathBuf}; use anyhow::Result; use url::Url; -use distribution_types::{IndexLocations, InstalledDist, Requirement, Resolution, SourceDist}; +use distribution_types::{ + CachedDist, IndexLocations, InstalledDist, Requirement, Resolution, SourceDist, +}; use pep508_rs::PackageName; use uv_cache::Cache; use uv_configuration::{BuildKind, NoBinary, NoBuild, SetupPyStrategy}; @@ -88,7 +90,7 @@ pub trait BuildContext { &'a self, resolution: &'a Resolution, venv: &'a PythonEnvironment, - ) -> impl Future> + 'a; + ) -> impl Future>> + 'a; /// Setup a source distribution build by installing the required dependencies. A wrapper for /// `uv_build::SourceBuild::setup`. diff --git a/crates/uv/src/commands/venv.rs b/crates/uv/src/commands/venv.rs index 5486e9de9..06129124d 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -5,12 +5,11 @@ use std::vec; use anstream::eprint; use anyhow::Result; -use itertools::Itertools; use miette::{Diagnostic, IntoDiagnostic}; use owo_colors::OwoColorize; use thiserror::Error; -use distribution_types::{DistributionMetadata, IndexLocations, Name, Requirement, ResolvedDist}; +use distribution_types::{IndexLocations, Requirement}; use install_wheel_rs::linker::LinkMode; use uv_auth::store_credentials_from_url; use uv_cache::Cache; @@ -25,7 +24,7 @@ use uv_interpreter::{ use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex, OptionsBuilder}; use uv_types::{BuildContext, BuildIsolation, HashStrategy, InFlight}; -use crate::commands::ExitStatus; +use crate::commands::{pip, ExitStatus}; use crate::printer::Printer; use crate::shell::Shell; @@ -223,50 +222,36 @@ async fn venv_impl( .with_options(OptionsBuilder::new().exclude_newer(exclude_newer).build()); // Resolve the seed packages. - let mut requirements = + let requirements = if interpreter.python_tuple() < (3, 12) { + // Only include `setuptools` and `wheel` on Python <3.12 vec![ Requirement::from_pep508(pep508_rs::Requirement::from_str("pip").unwrap()).unwrap(), - ]; - - // Only include `setuptools` and `wheel` on Python <3.12 - if interpreter.python_tuple() < (3, 12) { - requirements.push( Requirement::from_pep508(pep508_rs::Requirement::from_str("setuptools").unwrap()) .unwrap(), - ); - requirements.push( Requirement::from_pep508(pep508_rs::Requirement::from_str("wheel").unwrap()) .unwrap(), - ); - } + ] + } else { + vec![ + Requirement::from_pep508(pep508_rs::Requirement::from_str("pip").unwrap()).unwrap(), + ] + }; + + // Resolve and install the requirements. + // + // Since the virtual environment is empty, and the set of requirements is trivial (no + // constraints, no editables, etc.), we can use the build dispatch APIs directly. let resolution = build_dispatch .resolve(&requirements) .await .map_err(VenvError::Seed)?; - - // Install into the environment. - build_dispatch + let installed = build_dispatch .install(&resolution, &venv) .await .map_err(VenvError::Seed)?; - for distribution in resolution - .distributions() - .filter_map(|dist| match dist { - ResolvedDist::Installable(dist) => Some(dist), - ResolvedDist::Installed(_) => None, - }) - .sorted_unstable_by(|a, b| a.name().cmp(b.name()).then(a.version().cmp(&b.version()))) - { - writeln!( - printer.stderr(), - " {} {}{}", - "+".green(), - distribution.name().as_ref().bold(), - distribution.version_or_url().dimmed() - ) + pip::operations::report_modifications(installed, Vec::new(), Vec::new(), printer) .into_diagnostic()?; - } } // Determine the appropriate activation command.