Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6397,9 +6397,10 @@ pub struct ToolUpgradeArgs {
/// in which start time is critical, such as CLI applications and Docker containers, this option
/// can be enabled to trade longer installation times for faster start times.
///
/// When enabled, uv will process the entire site-packages directory (including packages that
/// are not being modified by the current operation) for consistency. Like pip, it will also
/// ignore errors.
/// When enabled, uv will compile the installed Python files required by the command. `uv pip
/// install` limits compilation to packages installed by the current operation, while project
/// and environment sync commands process the entire site-packages directory. Like pip,
/// compilation errors are ignored.
Comment thread
zanieb marked this conversation as resolved.
Outdated
#[arg(
long,
alias = "compile",
Expand Down Expand Up @@ -7468,9 +7469,10 @@ pub struct InstallerArgs {
/// in which start time is critical, such as CLI applications and Docker containers, this option
/// can be enabled to trade longer installation times for faster start times.
///
/// When enabled, uv will process the entire site-packages directory (including packages that
/// are not being modified by the current operation) for consistency. Like pip, it will also
/// ignore errors.
/// When enabled, uv will compile the installed Python files required by the command. `uv pip
/// install` limits compilation to packages installed by the current operation, while project
/// and environment sync commands process the entire site-packages directory. Like pip,
/// compilation errors are ignored.
#[arg(
long,
alias = "compile",
Expand Down Expand Up @@ -7965,9 +7967,10 @@ pub struct ResolverInstallerArgs {
/// in which start time is critical, such as CLI applications and Docker containers, this option
/// can be enabled to trade longer installation times for faster start times.
///
/// When enabled, uv will process the entire site-packages directory (including packages that
/// are not being modified by the current operation) for consistency. Like pip, it will also
/// ignore errors.
/// When enabled, uv will compile the installed Python files required by the command. `uv pip
/// install` limits compilation to packages installed by the current operation, while project
/// and environment sync commands process the entire site-packages directory. Like pip,
/// compilation errors are ignored.
#[arg(
long,
alias = "compile",
Expand Down
51 changes: 31 additions & 20 deletions crates/uv-install-wheel/src/install.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Like `wheel.rs`, but for installing wheels that have already been unzipped, rather than
//! reading from a zip file.

use std::path::Path;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use fs_err::File;
Expand All @@ -18,6 +18,30 @@ use crate::wheel::{
};
use crate::{Error, Layout};

/// Return the path at which the wheel's `.dist-info` directory will be installed.
pub fn installed_dist_info_path(
layout: &Layout,
wheel: impl AsRef<Path>,
) -> Result<PathBuf, Error> {
let (dist_info_prefix, site_packages) = wheel_destination(layout, wheel.as_ref())?;
Ok(site_packages.join(format!("{dist_info_prefix}.dist-info")))
}

/// Return the wheel's `.dist-info` prefix and target `site-packages` directory.
fn wheel_destination<'layout>(
layout: &'layout Layout,
wheel: &Path,
) -> Result<(String, &'layout Path), Error> {
let dist_info_prefix = find_dist_info(wheel)?;
let wheel_file_path = wheel.join(format!("{dist_info_prefix}.dist-info/WHEEL"));
let wheel_text = fs_err::read_to_string(wheel_file_path)?;
let site_packages = match WheelFile::parse(&wheel_text)?.lib_kind() {
LibKind::Pure => &layout.scheme.purelib,
LibKind::Plat => &layout.scheme.platlib,
};
Ok((dist_info_prefix, site_packages))
}

/// Install the given wheel to the given venv
///
/// The caller must ensure that the wheel is compatible to the environment.
Expand All @@ -39,8 +63,9 @@ pub fn install_wheel<Cache: serde::Serialize, Build: serde::Serialize>(
link_mode: LinkMode,
state: &InstallState,
) -> Result<(), Error> {
let dist_info_prefix = find_dist_info(&wheel)?;
let metadata = dist_info_metadata(&dist_info_prefix, &wheel)?;
let wheel = wheel.as_ref();
let (dist_info_prefix, site_packages) = wheel_destination(layout, wheel)?;
let metadata = dist_info_metadata(&dist_info_prefix, wheel)?;
let Metadata10 { name, version } = Metadata10::parse_pkg_info(&metadata)
.map_err(|err| Error::InvalidWheel(err.to_string()))?;

Expand All @@ -61,32 +86,18 @@ pub fn install_wheel<Cache: serde::Serialize, Build: serde::Serialize>(
// https://packaging.python.org/en/latest/specifications/binary-distribution-format/#installing-a-wheel-distribution-1-0-py32-none-any-whl
// > 1.a Parse distribution-1.0.dist-info/WHEEL.
// > 1.b Check that installer is compatible with Wheel-Version. Warn if minor version is greater, abort if major version is greater.
let wheel_file_path = wheel
.as_ref()
.join(format!("{dist_info_prefix}.dist-info/WHEEL"));
let wheel_text = fs_err::read_to_string(wheel_file_path)?;
let lib_kind = WheelFile::parse(&wheel_text)?.lib_kind();

// > 1.c If Root-Is-Purelib == ‘true’, unpack archive into purelib (site-packages).
// > 1.d Else unpack archive into platlib (site-packages).
trace!(?name, "Extracting wheel files");
let site_packages = match lib_kind {
LibKind::Pure => &layout.scheme.purelib,
LibKind::Plat => &layout.scheme.platlib,
};
link_wheel_files(link_mode, site_packages, &wheel, state, filename)?;
link_wheel_files(link_mode, site_packages, wheel, state, filename)?;
trace!(?name, "Extracted wheel files");

// Read the RECORD file.
let mut record_file = File::open(
wheel
.as_ref()
.join(format!("{dist_info_prefix}.dist-info/RECORD")),
)?;
let mut record_file = File::open(wheel.join(format!("{dist_info_prefix}.dist-info/RECORD")))?;
let mut record = read_record(&mut record_file)?;

let (console_scripts, gui_scripts) =
parse_scripts(&wheel, &dist_info_prefix, None, layout.python_version.1)?;
parse_scripts(wheel, &dist_info_prefix, None, layout.python_version.1)?;

if console_scripts.is_empty() && gui_scripts.is_empty() {
trace!(?name, "No entrypoints");
Expand Down
4 changes: 2 additions & 2 deletions crates/uv-install-wheel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_pypi_types::Scheme;

pub use install::install_wheel;
pub use install::{install_wheel, installed_dist_info_path};
pub use linker::{InstallState, LinkMode};
pub use record::RecordEntry;
pub use uninstall::{Uninstall, uninstall_egg, uninstall_legacy_editable, uninstall_wheel};
pub use wheel::{WheelFile, read_record, validate_and_heal_record};
pub use wheel::{WheelFile, read_record, read_record_iter, validate_and_heal_record};

mod install;
mod linker;
Expand Down
9 changes: 6 additions & 3 deletions crates/uv-install-wheel/src/wheel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,12 +841,12 @@ fn get_relocatable_executable(

/// Reads the record file
/// <https://www.python.org/dev/peps/pep-0376/#record>
pub fn read_record(record: impl Read) -> Result<Vec<RecordEntry>, Error> {
pub fn read_record_iter(record: impl Read) -> impl Iterator<Item = Result<RecordEntry, Error>> {
Comment thread
zanieb marked this conversation as resolved.
Outdated
csv::ReaderBuilder::new()
.has_headers(false)
.escape(Some(b'"'))
.from_reader(record)
.deserialize()
.into_deserialize()
.map(|entry| {
let entry: RecordEntry = entry?;
Ok(RecordEntry {
Expand All @@ -855,7 +855,10 @@ pub fn read_record(record: impl Read) -> Result<Vec<RecordEntry>, Error> {
..entry
})
})
.collect()
}

pub fn read_record(record: impl Read) -> Result<Vec<RecordEntry>, Error> {
read_record_iter(record).collect()
}

pub(crate) fn write_record(
Expand Down
Loading
Loading