mirror of https://github.com/astral-sh/uv
Move WHEEL file parsing into a struct (#15483)
## Summary No functional changes, but I need to add more behavior here for https://github.com/astral-sh/uv/issues/15035, so seems nice to do this separately.
This commit is contained in:
parent
f16760e10a
commit
6d874b1a25
|
|
@ -14,7 +14,7 @@ use uv_pypi_types::{DirectUrl, Metadata10};
|
||||||
|
|
||||||
use crate::linker::{LinkMode, Locks};
|
use crate::linker::{LinkMode, Locks};
|
||||||
use crate::wheel::{
|
use crate::wheel::{
|
||||||
LibKind, dist_info_metadata, find_dist_info, install_data, parse_scripts, parse_wheel_file,
|
LibKind, WheelFile, dist_info_metadata, find_dist_info, install_data, parse_scripts,
|
||||||
read_record_file, write_installer_metadata, write_script_entrypoints,
|
read_record_file, write_installer_metadata, write_script_entrypoints,
|
||||||
};
|
};
|
||||||
use crate::{Error, Layout};
|
use crate::{Error, Layout};
|
||||||
|
|
@ -66,7 +66,7 @@ pub fn install_wheel<Cache: serde::Serialize, Build: serde::Serialize>(
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.join(format!("{dist_info_prefix}.dist-info/WHEEL"));
|
.join(format!("{dist_info_prefix}.dist-info/WHEEL"));
|
||||||
let wheel_text = fs::read_to_string(wheel_file_path)?;
|
let wheel_text = fs::read_to_string(wheel_file_path)?;
|
||||||
let lib_kind = parse_wheel_file(&wheel_text)?;
|
let lib_kind = WheelFile::parse(&wheel_text)?.lib_kind();
|
||||||
|
|
||||||
// > 1.c If Root-Is-Purelib == ‘true’, unpack archive into purelib (site-packages).
|
// > 1.c If Root-Is-Purelib == ‘true’, unpack archive into purelib (site-packages).
|
||||||
// > 1.d Else unpack archive into platlib (site-packages).
|
// > 1.d Else unpack archive into platlib (site-packages).
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use uv_pypi_types::Scheme;
|
||||||
pub use install::install_wheel;
|
pub use install::install_wheel;
|
||||||
pub use linker::{LinkMode, Locks};
|
pub use linker::{LinkMode, Locks};
|
||||||
pub use uninstall::{Uninstall, uninstall_egg, uninstall_legacy_editable, uninstall_wheel};
|
pub use uninstall::{Uninstall, uninstall_egg, uninstall_legacy_editable, uninstall_wheel};
|
||||||
pub use wheel::{LibKind, parse_wheel_file, read_record_file};
|
pub use wheel::{LibKind, WheelFile, read_record_file};
|
||||||
|
|
||||||
mod install;
|
mod install;
|
||||||
mod linker;
|
mod linker;
|
||||||
|
|
|
||||||
|
|
@ -257,35 +257,19 @@ pub(crate) fn write_script_entrypoints(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the wheel should be installed into the `purelib` or `platlib` directory.
|
/// A parsed `WHEEL` file.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum LibKind {
|
pub struct WheelFile(FxHashMap<String, Vec<String>>);
|
||||||
/// Install into the `purelib` directory.
|
|
||||||
Pure,
|
|
||||||
/// Install into the `platlib` directory.
|
|
||||||
Plat,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse WHEEL file.
|
impl WheelFile {
|
||||||
|
/// Parse `WHEEL` file.
|
||||||
///
|
///
|
||||||
/// > {distribution}-{version}.dist-info/WHEEL is metadata about the archive itself in the same
|
/// > {distribution}-{version}.dist-info/WHEEL is metadata about the archive itself in the same
|
||||||
/// > email message format:
|
/// > email message format:
|
||||||
pub fn parse_wheel_file(wheel_text: &str) -> Result<LibKind, Error> {
|
pub fn parse(wheel_text: &str) -> Result<Self, Error> {
|
||||||
// {distribution}-{version}.dist-info/WHEEL is metadata about the archive itself in the same email message format:
|
// {distribution}-{version}.dist-info/WHEEL is metadata about the archive itself in the same email message format:
|
||||||
let data = parse_email_message_file(&mut wheel_text.as_bytes(), "WHEEL")?;
|
let data = parse_email_message_file(&mut wheel_text.as_bytes(), "WHEEL")?;
|
||||||
|
|
||||||
// Determine whether Root-Is-Purelib == ‘true’.
|
|
||||||
// If it is, the wheel is pure, and should be installed into purelib.
|
|
||||||
let root_is_purelib = data
|
|
||||||
.get("Root-Is-Purelib")
|
|
||||||
.and_then(|root_is_purelib| root_is_purelib.first())
|
|
||||||
.is_some_and(|root_is_purelib| root_is_purelib == "true");
|
|
||||||
let lib_kind = if root_is_purelib {
|
|
||||||
LibKind::Pure
|
|
||||||
} else {
|
|
||||||
LibKind::Plat
|
|
||||||
};
|
|
||||||
|
|
||||||
// mkl_fft-1.3.6-58-cp310-cp310-manylinux2014_x86_64.whl has multiple Wheel-Version entries, we have to ignore that
|
// mkl_fft-1.3.6-58-cp310-cp310-manylinux2014_x86_64.whl has multiple Wheel-Version entries, we have to ignore that
|
||||||
// like pip
|
// like pip
|
||||||
let wheel_version = data
|
let wheel_version = data
|
||||||
|
|
@ -302,7 +286,7 @@ pub fn parse_wheel_file(wheel_text: &str) -> Result<LibKind, Error> {
|
||||||
// and technically we only need to check that the version is not higher
|
// and technically we only need to check that the version is not higher
|
||||||
if wheel_version == ("0", "1") {
|
if wheel_version == ("0", "1") {
|
||||||
warn!("Ancient wheel version 0.1 (expected is 1.0)");
|
warn!("Ancient wheel version 0.1 (expected is 1.0)");
|
||||||
return Ok(lib_kind);
|
return Ok(Self(data));
|
||||||
}
|
}
|
||||||
// Check that installer is compatible with Wheel-Version. Warn if minor version is greater, abort if major version is greater.
|
// Check that installer is compatible with Wheel-Version. Warn if minor version is greater, abort if major version is greater.
|
||||||
// Wheel-Version: 1.0
|
// Wheel-Version: 1.0
|
||||||
|
|
@ -318,7 +302,38 @@ pub fn parse_wheel_file(wheel_text: &str) -> Result<LibKind, Error> {
|
||||||
0, wheel_version.1
|
0, wheel_version.1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(lib_kind)
|
Ok(Self(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the wheel should be installed into the `purelib` or `platlib` directory.
|
||||||
|
pub fn lib_kind(&self) -> LibKind {
|
||||||
|
// Determine whether Root-Is-Purelib == ‘true’.
|
||||||
|
// If it is, the wheel is pure, and should be installed into purelib.
|
||||||
|
let root_is_purelib = self
|
||||||
|
.0
|
||||||
|
.get("Root-Is-Purelib")
|
||||||
|
.and_then(|root_is_purelib| root_is_purelib.first())
|
||||||
|
.is_some_and(|root_is_purelib| root_is_purelib == "true");
|
||||||
|
if root_is_purelib {
|
||||||
|
LibKind::Pure
|
||||||
|
} else {
|
||||||
|
LibKind::Plat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the list of wheel tags.
|
||||||
|
pub fn tags(&self) -> Option<&[String]> {
|
||||||
|
self.0.get("Tag").map(Vec::as_slice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the wheel should be installed into the `purelib` or `platlib` directory.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum LibKind {
|
||||||
|
/// Install into the `purelib` directory.
|
||||||
|
Pure,
|
||||||
|
/// Install into the `platlib` directory.
|
||||||
|
Plat,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the files and folders in src to dest, updating the RECORD in the process
|
/// Moves the files and folders in src to dest, updating the RECORD in the process
|
||||||
|
|
@ -938,7 +953,7 @@ mod test {
|
||||||
use crate::wheel::format_shebang;
|
use crate::wheel::format_shebang;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
RecordEntry, Script, get_script_executable, parse_email_message_file, parse_wheel_file,
|
RecordEntry, Script, WheelFile, get_script_executable, parse_email_message_file,
|
||||||
read_record_file, write_installer_metadata,
|
read_record_file, write_installer_metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1013,8 +1028,8 @@ mod test {
|
||||||
version
|
version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parse_wheel_file(&wheel_with_version("1.0")).unwrap();
|
WheelFile::parse(&wheel_with_version("1.0")).unwrap();
|
||||||
parse_wheel_file(&wheel_with_version("2.0")).unwrap_err();
|
WheelFile::parse(&wheel_with_version("2.0")).unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue