mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
Add source distribution filename abstraction (#154)
The need for this became clear when working on the source distribution integration into the resolver. While at it i also switch the `WheelFilename` version to the parsed `pep440_rs` version now that we have this crate.
This commit is contained in:
parent
6f52b5ca4d
commit
ae9d1f7572
19 changed files with 220 additions and 58 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -676,6 +676,16 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "distribution-filename"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"pep440_rs 0.3.12",
|
||||||
|
"platform-tags",
|
||||||
|
"puffin-package",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "doc-comment"
|
name = "doc-comment"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -990,6 +1000,7 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"configparser",
|
"configparser",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"distribution-filename",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"install-wheel-rs",
|
"install-wheel-rs",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
@ -1001,7 +1012,6 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"wheel-filename",
|
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1322,6 +1332,7 @@ dependencies = [
|
||||||
"configparser",
|
"configparser",
|
||||||
"csv",
|
"csv",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
|
"distribution-filename",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"fs2",
|
"fs2",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
|
@ -1346,7 +1357,6 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"wheel-filename",
|
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2101,6 +2111,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cacache",
|
"cacache",
|
||||||
|
"distribution-filename",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"install-wheel-rs",
|
"install-wheel-rs",
|
||||||
"pep440_rs 0.3.12",
|
"pep440_rs 0.3.12",
|
||||||
|
@ -2113,7 +2124,6 @@ dependencies = [
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"wheel-filename",
|
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2164,6 +2174,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"colored",
|
"colored",
|
||||||
|
"distribution-filename",
|
||||||
"futures",
|
"futures",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
"insta",
|
"insta",
|
||||||
|
@ -2180,7 +2191,6 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"waitmap",
|
"waitmap",
|
||||||
"wheel-filename",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3557,14 +3567,6 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wheel-filename"
|
|
||||||
version = "0.0.1"
|
|
||||||
dependencies = [
|
|
||||||
"platform-tags",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
version = "4.4.2"
|
version = "4.4.2"
|
||||||
|
|
|
@ -40,6 +40,6 @@ Types and functionality for working with Python packages, e.g., parsing wheel fi
|
||||||
|
|
||||||
Functionality for resolving Python packages and their dependencies.
|
Functionality for resolving Python packages and their dependencies.
|
||||||
|
|
||||||
## [wheel-filename](./wheel-filename)
|
## [distribution-filename](./distribution-filename)
|
||||||
|
|
||||||
Functionality for parsing wheel filenames as per [PEP 427](https://peps.python.org/pep-0427/).
|
Functionality for parsing wheel filenames as per [PEP 427](https://peps.python.org/pep-0427/).
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "wheel-filename"
|
name = "distribution-filename"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
@ -11,5 +11,7 @@ license = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
platform-tags = { path = "../platform-tags" }
|
platform-tags = { path = "../platform-tags" }
|
||||||
|
puffin-package = { path = "../puffin-package" }
|
||||||
|
pep440_rs = { path = "../pep440-rs" }
|
||||||
|
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
7
crates/distribution-filename/src/lib.rs
Normal file
7
crates/distribution-filename/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
pub use source_distribution::{
|
||||||
|
SourceDistributionExtension, SourceDistributionFilename, SourceDistributionFilenameError,
|
||||||
|
};
|
||||||
|
pub use wheel_filename::{WheelFilename, WheelFilenameError};
|
||||||
|
|
||||||
|
mod source_distribution;
|
||||||
|
mod wheel_filename;
|
142
crates/distribution-filename/src/source_distribution.rs
Normal file
142
crates/distribution-filename/src/source_distribution.rs
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
use pep440_rs::Version;
|
||||||
|
use puffin_package::package_name::PackageName;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum SourceDistributionExtension {
|
||||||
|
Zip,
|
||||||
|
TarGz,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for SourceDistributionExtension {
|
||||||
|
type Err = SourceDistributionFilenameError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"zip" => Self::Zip,
|
||||||
|
"tar.gz" => Self::TarGz,
|
||||||
|
other => {
|
||||||
|
return Err(SourceDistributionFilenameError::InvalidExtension(
|
||||||
|
other.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SourceDistributionExtension {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
SourceDistributionExtension::Zip => f.write_str("zip"),
|
||||||
|
SourceDistributionExtension::TarGz => f.write_str("tar.gz"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceDistributionExtension {
|
||||||
|
pub fn from_filename(filename: &str) -> Option<(&str, Self)> {
|
||||||
|
if let Some(stem) = filename.strip_suffix(".zip") {
|
||||||
|
return Some((stem, Self::Zip));
|
||||||
|
}
|
||||||
|
if let Some(stem) = filename.strip_suffix(".tar.gz") {
|
||||||
|
return Some((stem, Self::TarGz));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Note that this is a normalized and not an exact representation, keep the original string if you
|
||||||
|
/// need the latter.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct SourceDistributionFilename {
|
||||||
|
pub name: PackageName,
|
||||||
|
pub version: Version,
|
||||||
|
pub extension: SourceDistributionExtension,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceDistributionFilename {
|
||||||
|
/// No `FromStr` impl since we need to know the package name to be able to reasonable parse
|
||||||
|
/// these (consider e.g. `a-1-1.zip`)
|
||||||
|
pub fn parse(
|
||||||
|
filename: &str,
|
||||||
|
package_name: &PackageName,
|
||||||
|
) -> Result<Self, SourceDistributionFilenameError> {
|
||||||
|
let Some((stem, extension)) = SourceDistributionExtension::from_filename(filename) else {
|
||||||
|
return Err(SourceDistributionFilenameError::InvalidExtension(
|
||||||
|
filename.to_string(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if stem.len() <= package_name.as_ref().len() + "-".len()
|
||||||
|
|| &PackageName::normalize(&stem[..package_name.as_ref().len()]) != package_name
|
||||||
|
{
|
||||||
|
return Err(SourceDistributionFilenameError::InvalidFilename {
|
||||||
|
filename: filename.to_string(),
|
||||||
|
package_name: package_name.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// We checked the length above
|
||||||
|
let version = Version::from_str(&stem[package_name.as_ref().len() + "-".len()..])
|
||||||
|
.map_err(SourceDistributionFilenameError::InvalidVersion)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
name: package_name.clone(),
|
||||||
|
version,
|
||||||
|
extension,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SourceDistributionFilename {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}-{}.{}", self.name, self.version, self.extension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug, Clone)]
|
||||||
|
pub enum SourceDistributionFilenameError {
|
||||||
|
#[error("Source distribution name {filename} doesn't start with package name {package_name}")]
|
||||||
|
InvalidFilename {
|
||||||
|
filename: String,
|
||||||
|
package_name: String,
|
||||||
|
},
|
||||||
|
#[error("Source distributions filenames must end with .zip or .tar.gz, not {0}")]
|
||||||
|
InvalidExtension(String),
|
||||||
|
#[error("Source distribution filename version section is invalid: {0}")]
|
||||||
|
InvalidVersion(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::SourceDistributionFilename;
|
||||||
|
use puffin_package::package_name::PackageName;
|
||||||
|
|
||||||
|
/// Only test already normalized names since the parsing is lossy
|
||||||
|
#[test]
|
||||||
|
fn roundtrip() {
|
||||||
|
for normalized in [
|
||||||
|
"foo-lib-1.2.3.zip",
|
||||||
|
"foo-lib-1.2.3a3.zip",
|
||||||
|
"foo-lib-1.2.3.tar.gz",
|
||||||
|
] {
|
||||||
|
assert_eq!(
|
||||||
|
SourceDistributionFilename::parse(normalized, &PackageName::normalize("foo_lib"))
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
normalized
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn errors() {
|
||||||
|
for invalid in ["b-1.2.3.zip", "a-1.2.3-gamma.3.zip", "a-1.2.3.tar.zstd"] {
|
||||||
|
assert!(
|
||||||
|
SourceDistributionFilename::parse(invalid, &PackageName::normalize("a")).is_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use pep440_rs::Version;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use platform_tags::Tags;
|
use platform_tags::Tags;
|
||||||
|
@ -7,31 +9,38 @@ use platform_tags::Tags;
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct WheelFilename {
|
pub struct WheelFilename {
|
||||||
pub distribution: String,
|
pub distribution: String,
|
||||||
pub version: String,
|
pub version: Version,
|
||||||
pub python_tag: Vec<String>,
|
pub python_tag: Vec<String>,
|
||||||
pub abi_tag: Vec<String>,
|
pub abi_tag: Vec<String>,
|
||||||
pub platform_tag: Vec<String>,
|
pub platform_tag: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for WheelFilename {
|
impl FromStr for WheelFilename {
|
||||||
type Err = Error;
|
type Err = WheelFilenameError;
|
||||||
|
|
||||||
fn from_str(filename: &str) -> Result<Self, Self::Err> {
|
fn from_str(filename: &str) -> Result<Self, Self::Err> {
|
||||||
let basename = filename.strip_suffix(".whl").ok_or_else(|| {
|
let basename = filename.strip_suffix(".whl").ok_or_else(|| {
|
||||||
Error::InvalidWheelFileName(filename.to_string(), "Must end with .whl".to_string())
|
WheelFilenameError::InvalidWheelFileName(
|
||||||
|
filename.to_string(),
|
||||||
|
"Must end with .whl".to_string(),
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
// https://www.python.org/dev/peps/pep-0427/#file-name-convention
|
// https://www.python.org/dev/peps/pep-0427/#file-name-convention
|
||||||
match basename.split('-').collect::<Vec<_>>().as_slice() {
|
match basename.split('-').collect::<Vec<_>>().as_slice() {
|
||||||
// TODO(charlie): Build tag precedence
|
// TODO(charlie): Build tag precedence
|
||||||
&[distribution, version, _, python_tag, abi_tag, platform_tag]
|
&[distribution, version, _, python_tag, abi_tag, platform_tag]
|
||||||
| &[distribution, version, python_tag, abi_tag, platform_tag] => Ok(WheelFilename {
|
| &[distribution, version, python_tag, abi_tag, platform_tag] => {
|
||||||
distribution: distribution.to_string(),
|
let version = Version::from_str(version)
|
||||||
version: version.to_string(),
|
.map_err(|err| WheelFilenameError::InvalidVersion(filename.to_string(), err))?;
|
||||||
python_tag: python_tag.split('.').map(String::from).collect(),
|
Ok(WheelFilename {
|
||||||
abi_tag: abi_tag.split('.').map(String::from).collect(),
|
distribution: distribution.to_string(),
|
||||||
platform_tag: platform_tag.split('.').map(String::from).collect(),
|
version,
|
||||||
}),
|
python_tag: python_tag.split('.').map(String::from).collect(),
|
||||||
_ => Err(Error::InvalidWheelFileName(
|
abi_tag: abi_tag.split('.').map(String::from).collect(),
|
||||||
|
platform_tag: platform_tag.split('.').map(String::from).collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => Err(WheelFilenameError::InvalidWheelFileName(
|
||||||
filename.to_string(),
|
filename.to_string(),
|
||||||
"Expected four \"-\" in the filename".to_string(),
|
"Expected four \"-\" in the filename".to_string(),
|
||||||
)),
|
)),
|
||||||
|
@ -39,6 +48,18 @@ impl FromStr for WheelFilename {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for WheelFilename {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}-{}-{}.whl",
|
||||||
|
self.distribution,
|
||||||
|
self.version,
|
||||||
|
self.get_tag()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WheelFilename {
|
impl WheelFilename {
|
||||||
/// Returns `true` if the wheel is compatible with the given tags.
|
/// Returns `true` if the wheel is compatible with the given tags.
|
||||||
pub fn is_compatible(&self, compatible_tags: &Tags) -> bool {
|
pub fn is_compatible(&self, compatible_tags: &Tags) -> bool {
|
||||||
|
@ -65,7 +86,9 @@ impl WheelFilename {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum WheelFilenameError {
|
||||||
#[error("The wheel filename \"{0}\" is invalid: {1}")]
|
#[error("The wheel filename \"{0}\" is invalid: {1}")]
|
||||||
InvalidWheelFileName(String, String),
|
InvalidWheelFileName(String, String),
|
||||||
|
#[error("The wheel filename \"{0}\" has an invalid version part: {1}")]
|
||||||
|
InvalidVersion(String, String),
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ license = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
install-wheel-rs = { path = "../install-wheel-rs", optional = true }
|
install-wheel-rs = { path = "../install-wheel-rs", optional = true }
|
||||||
wheel-filename = { path = "../wheel-filename" }
|
distribution-filename = { path = "../distribution-filename" }
|
||||||
|
|
||||||
camino = { workspace = true }
|
camino = { workspace = true }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
|
|
|
@ -10,8 +10,8 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
use distribution_filename::WheelFilename;
|
||||||
use install_wheel_rs::{install_wheel, InstallLocation};
|
use install_wheel_rs::{install_wheel, InstallLocation};
|
||||||
use wheel_filename::WheelFilename;
|
|
||||||
|
|
||||||
use crate::bare::VenvPaths;
|
use crate::bare::VenvPaths;
|
||||||
use crate::interpreter::InterpreterInfo;
|
use crate::interpreter::InterpreterInfo;
|
||||||
|
|
|
@ -18,7 +18,7 @@ name = "install_wheel_rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
platform-host = { path = "../platform-host" }
|
platform-host = { path = "../platform-host" }
|
||||||
wheel-filename = { path = "../wheel-filename" }
|
distribution-filename = { path = "../distribution-filename" }
|
||||||
|
|
||||||
clap = { workspace = true, optional = true, features = ["derive", "env"] }
|
clap = { workspace = true, optional = true, features = ["derive", "env"] }
|
||||||
configparser = { workspace = true }
|
configparser = { workspace = true }
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub enum Error {
|
||||||
InvalidPoetry(String),
|
InvalidPoetry(String),
|
||||||
/// Doesn't follow file name schema
|
/// Doesn't follow file name schema
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
InvalidWheelFileName(#[from] wheel_filename::Error),
|
InvalidWheelFileName(#[from] distribution_filename::WheelFilenameError),
|
||||||
#[error("Failed to read the wheel file {0}")]
|
#[error("Failed to read the wheel file {0}")]
|
||||||
Zip(String, #[source] ZipError),
|
Zip(String, #[source] ZipError),
|
||||||
#[error("Failed to run python subcommand")]
|
#[error("Failed to run python subcommand")]
|
||||||
|
|
|
@ -6,8 +6,8 @@ use fs_err::File;
|
||||||
#[cfg(feature = "rayon")]
|
#[cfg(feature = "rayon")]
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
|
use distribution_filename::WheelFilename;
|
||||||
use install_wheel_rs::{install_wheel, Error, InstallLocation};
|
use install_wheel_rs::{install_wheel, Error, InstallLocation};
|
||||||
use wheel_filename::WheelFilename;
|
|
||||||
|
|
||||||
/// Low level install CLI, mainly used for testing
|
/// Low level install CLI, mainly used for testing
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![allow(clippy::format_push_string)] // I will not replace clear and infallible with fallible, io looking code
|
#![allow(clippy::format_push_string)] // I will not replace clear and infallible with fallible, io looking code
|
||||||
|
|
||||||
use crate::{install_wheel, Error, InstallLocation, LockedDir};
|
use crate::{install_wheel, Error, InstallLocation, LockedDir};
|
||||||
|
use distribution_filename::WheelFilename;
|
||||||
use fs_err::File;
|
use fs_err::File;
|
||||||
use pyo3::create_exception;
|
use pyo3::create_exception;
|
||||||
use pyo3::types::PyModule;
|
use pyo3::types::PyModule;
|
||||||
|
@ -8,7 +9,6 @@ use pyo3::{pyclass, pymethods, pymodule, PyErr, PyResult, Python};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use wheel_filename::WheelFilename;
|
|
||||||
|
|
||||||
create_exception!(
|
create_exception!(
|
||||||
install_wheel_rs,
|
install_wheel_rs,
|
||||||
|
|
|
@ -19,7 +19,7 @@ use zip::result::ZipError;
|
||||||
use zip::write::FileOptions;
|
use zip::write::FileOptions;
|
||||||
use zip::{ZipArchive, ZipWriter};
|
use zip::{ZipArchive, ZipWriter};
|
||||||
|
|
||||||
use wheel_filename::WheelFilename;
|
use distribution_filename::WheelFilename;
|
||||||
|
|
||||||
use crate::install_location::{InstallLocation, LockedDir};
|
use crate::install_location::{InstallLocation, LockedDir};
|
||||||
use crate::record::RecordEntry;
|
use crate::record::RecordEntry;
|
||||||
|
|
|
@ -326,7 +326,7 @@ impl SourceDistributionBuilder {
|
||||||
let wheel = stdout
|
let wheel = stdout
|
||||||
.lines()
|
.lines()
|
||||||
.last()
|
.last()
|
||||||
.map(|wheel_filename| wheel_dir.join(wheel_filename));
|
.map(|distribution_filename| wheel_dir.join(distribution_filename));
|
||||||
let Some(wheel) = wheel.filter(|wheel| wheel.is_file()) else {
|
let Some(wheel) = wheel.filter(|wheel| wheel.is_file()) else {
|
||||||
return Err(Error::from_command_output(
|
return Err(Error::from_command_output(
|
||||||
"Build backend did not return the wheel filename through `build_wheel()`"
|
"Build backend did not return the wheel filename through `build_wheel()`"
|
||||||
|
|
|
@ -15,7 +15,7 @@ pep440_rs = { path = "../pep440-rs" }
|
||||||
puffin-client = { path = "../puffin-client" }
|
puffin-client = { path = "../puffin-client" }
|
||||||
puffin-interpreter = { path = "../puffin-interpreter" }
|
puffin-interpreter = { path = "../puffin-interpreter" }
|
||||||
puffin-package = { path = "../puffin-package" }
|
puffin-package = { path = "../puffin-package" }
|
||||||
wheel-filename = { path = "../wheel-filename" }
|
distribution-filename = { path = "../distribution-filename" }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
cacache = { workspace = true }
|
cacache = { workspace = true }
|
||||||
|
|
|
@ -3,11 +3,11 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
use distribution_filename::WheelFilename;
|
||||||
use pep440_rs::Version;
|
use pep440_rs::Version;
|
||||||
use puffin_client::File;
|
use puffin_client::File;
|
||||||
use puffin_package::dist_info_name::DistInfoName;
|
use puffin_package::dist_info_name::DistInfoName;
|
||||||
use puffin_package::package_name::PackageName;
|
use puffin_package::package_name::PackageName;
|
||||||
use wheel_filename::WheelFilename;
|
|
||||||
|
|
||||||
/// A built distribution (wheel), which either exists remotely or locally.
|
/// A built distribution (wheel), which either exists remotely or locally.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -79,10 +79,9 @@ impl RemoteDistribution {
|
||||||
pub fn from_file(file: File) -> Result<Self> {
|
pub fn from_file(file: File) -> Result<Self> {
|
||||||
let filename = WheelFilename::from_str(&file.filename)?;
|
let filename = WheelFilename::from_str(&file.filename)?;
|
||||||
let name = PackageName::normalize(&filename.distribution);
|
let name = PackageName::normalize(&filename.distribution);
|
||||||
let version = Version::from_str(&filename.version).map_err(|err| anyhow!(err))?;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
version,
|
version: filename.version.clone(),
|
||||||
file,
|
file,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ platform-tags = { path = "../platform-tags" }
|
||||||
pubgrub = { path = "../../vendor/pubgrub" }
|
pubgrub = { path = "../../vendor/pubgrub" }
|
||||||
puffin-client = { path = "../puffin-client" }
|
puffin-client = { path = "../puffin-client" }
|
||||||
puffin-package = { path = "../puffin-package" }
|
puffin-package = { path = "../puffin-package" }
|
||||||
wheel-filename = { path = "../wheel-filename" }
|
distribution-filename = { path = "../distribution-filename" }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
bitflags = { workspace = true }
|
bitflags = { workspace = true }
|
||||||
|
|
|
@ -18,13 +18,13 @@ use tokio::select;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
use waitmap::WaitMap;
|
use waitmap::WaitMap;
|
||||||
|
|
||||||
|
use distribution_filename::WheelFilename;
|
||||||
use pep508_rs::{MarkerEnvironment, Requirement};
|
use pep508_rs::{MarkerEnvironment, Requirement};
|
||||||
use platform_tags::Tags;
|
use platform_tags::Tags;
|
||||||
use puffin_client::{File, PypiClient, SimpleJson};
|
use puffin_client::{File, PypiClient, SimpleJson};
|
||||||
use puffin_package::dist_info_name::DistInfoName;
|
use puffin_package::dist_info_name::DistInfoName;
|
||||||
use puffin_package::metadata::Metadata21;
|
use puffin_package::metadata::Metadata21;
|
||||||
use puffin_package::package_name::PackageName;
|
use puffin_package::package_name::PackageName;
|
||||||
use wheel_filename::WheelFilename;
|
|
||||||
|
|
||||||
use crate::error::ResolveError;
|
use crate::error::ResolveError;
|
||||||
use crate::pubgrub::package::PubGrubPackage;
|
use crate::pubgrub::package::PubGrubPackage;
|
||||||
|
@ -268,17 +268,13 @@ impl<'a> Resolver<'a> {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(version) = pep440_rs::Version::from_str(&name.version) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if !name.is_compatible(self.tags) {
|
if !name.is_compatible(self.tags) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !range
|
if !range
|
||||||
.borrow()
|
.borrow()
|
||||||
.contains(&PubGrubVersion::from(version.clone()))
|
.contains(&PubGrubVersion::from(name.version.clone()))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -322,17 +318,13 @@ impl<'a> Resolver<'a> {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(version) = pep440_rs::Version::from_str(&name.version) else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
if !name.is_compatible(self.tags) {
|
if !name.is_compatible(self.tags) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !range
|
if !range
|
||||||
.borrow()
|
.borrow()
|
||||||
.contains(&PubGrubVersion::from(version.clone()))
|
.contains(&PubGrubVersion::from(name.version.clone()))
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
@ -340,7 +332,7 @@ impl<'a> Resolver<'a> {
|
||||||
Some(Wheel {
|
Some(Wheel {
|
||||||
file: file.clone(),
|
file: file.clone(),
|
||||||
name: package_name.clone(),
|
name: package_name.clone(),
|
||||||
version: version.clone(),
|
version: name.version.clone(),
|
||||||
})
|
})
|
||||||
}) else {
|
}) else {
|
||||||
// Short circuit: we couldn't find _any_ compatible versions for a package.
|
// Short circuit: we couldn't find _any_ compatible versions for a package.
|
||||||
|
|
|
@ -11,13 +11,12 @@ use futures::{StreamExt, TryFutureExt};
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use pep440_rs::Version;
|
use distribution_filename::WheelFilename;
|
||||||
use pep508_rs::Requirement;
|
use pep508_rs::Requirement;
|
||||||
use platform_tags::Tags;
|
use platform_tags::Tags;
|
||||||
use puffin_client::{File, PypiClient, SimpleJson};
|
use puffin_client::{File, PypiClient, SimpleJson};
|
||||||
use puffin_package::metadata::Metadata21;
|
use puffin_package::metadata::Metadata21;
|
||||||
use puffin_package::package_name::PackageName;
|
use puffin_package::package_name::PackageName;
|
||||||
use wheel_filename::WheelFilename;
|
|
||||||
|
|
||||||
use crate::error::ResolveError;
|
use crate::error::ResolveError;
|
||||||
use crate::resolution::{PinnedPackage, Resolution};
|
use crate::resolution::{PinnedPackage, Resolution};
|
||||||
|
@ -97,15 +96,11 @@ impl<'a> WheelFinder<'a> {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(version) = Version::from_str(&name.version) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if !name.is_compatible(self.tags) {
|
if !name.is_compatible(self.tags) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
requirement.is_satisfied_by(&version)
|
requirement.is_satisfied_by(&name.version)
|
||||||
}) else {
|
}) else {
|
||||||
return Err(ResolveError::NotFound(requirement));
|
return Err(ResolveError::NotFound(requirement));
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue