diff --git a/crates/puffin-client/tests/remote_metadata.rs b/crates/puffin-client/tests/remote_metadata.rs index 1bbf1b1db..1610f2374 100644 --- a/crates/puffin-client/tests/remote_metadata.rs +++ b/crates/puffin-client/tests/remote_metadata.rs @@ -10,22 +10,19 @@ use puffin_client::RegistryClientBuilder; #[tokio::test] async fn remote_metadata_with_and_without_cache() -> Result<()> { - let temp_cache = tempdir().unwrap(); + let temp_cache = tempdir()?; let client = RegistryClientBuilder::new(temp_cache.path().to_path_buf()).build(); + // The first run is without cache (the tempdir is empty), the second has the cache from the - // first run + // first run. for _ in 0..2 { let url = "https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl"; - let filename = WheelFilename::from_str(url.rsplit_once('/').unwrap().1).unwrap(); + let filename = WheelFilename::from_str(url.rsplit_once('/').unwrap().1)?; let metadata = client - .wheel_metadata_no_pep658( - &filename, - &Url::parse(url).unwrap(), - WheelMetadataCache::Url, - ) - .await - .unwrap(); - assert_eq!(metadata.summary.unwrap(), "Fast, Extensible Progress Meter"); + .wheel_metadata_no_pep658(&filename, &Url::parse(url)?, WheelMetadataCache::Url) + .await?; + assert_eq!(metadata.version.to_string(), "4.66.1"); } + Ok(()) } diff --git a/crates/pypi-types/src/metadata.rs b/crates/pypi-types/src/metadata.rs index 0423623b9..99fb2d4da 100644 --- a/crates/pypi-types/src/metadata.rs +++ b/crates/pypi-types/src/metadata.rs @@ -1,6 +1,5 @@ //! Derived from `pypi_types_crate`. -use std::collections::HashMap; use std::io; use std::str::FromStr; @@ -12,13 +11,14 @@ use pep440_rs::{Pep440Error, Version, VersionSpecifiers}; use pep508_rs::{Pep508Error, Requirement}; use puffin_normalize::{ExtraName, InvalidNameError, PackageName}; -use crate::lenient_requirement::{LenientRequirement, LenientVersionSpecifiers}; +use crate::lenient_requirement::LenientRequirement; +use crate::LenientVersionSpecifiers; /// Python Package Metadata 2.1 as specified in -/// +/// . /// -/// One addition is the requirements fixup which insert missing commas e.g. in -/// `elasticsearch-dsl (>=7.2.0<8.0.0)` +/// This is a subset of the full metadata specification, and only includes the +/// fields that are relevant to dependency resolution. #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct Metadata21 { @@ -27,26 +27,8 @@ pub struct Metadata21 { pub name: PackageName, pub version: Version, // Optional fields - pub platforms: Vec, - pub supported_platforms: Vec, - pub summary: Option, - pub description: Option, - pub description_content_type: Option, - pub keywords: Option, - pub home_page: Option, - pub download_url: Option, - pub author: Option, - pub author_email: Option, - pub maintainer: Option, - pub maintainer_email: Option, - pub license: Option, - pub classifiers: Vec, pub requires_dist: Vec, - pub provides_dist: Vec, - pub obsoletes_dist: Vec, pub requires_python: Option, - pub requires_external: Vec, - pub project_urls: HashMap, pub provides_extras: Vec, } @@ -99,6 +81,7 @@ impl Metadata21 { let msg = mailparse::parse_mail(&mail)?; let headers = msg.get_headers(); + let get_first_value = |name| { headers.get_first_header(name).and_then(|header| { match rfc2047_decoder::decode(header.get_value_raw()) { @@ -114,13 +97,12 @@ impl Metadata21 { }) }; let get_all_values = |name| { - let values: Vec = headers + headers .get_all_values(name) .into_iter() .filter(|value| value != "UNKNOWN") - .collect(); - values }; + let metadata_version = headers .get_first_value("Metadata-Version") .ok_or(Error::FieldNotFound("Metadata-Version"))?; @@ -135,75 +117,26 @@ impl Metadata21 { .ok_or(Error::FieldNotFound("Version"))?, ) .map_err(Error::Pep440VersionError)?; - let platforms = get_all_values("Platform"); - let supported_platforms = get_all_values("Supported-Platform"); - let summary = get_first_value("Summary"); - let body = msg.get_body()?; - let description = if body.trim().is_empty() { - get_first_value("Description") - } else { - Some(body) - }; - let keywords = get_first_value("Keywords"); - let home_page = get_first_value("Home-Page"); - let download_url = get_first_value("Download-URL"); - let author = get_first_value("Author"); - let author_email = get_first_value("Author-email"); - let license = get_first_value("License"); - let classifiers = get_all_values("Classifier"); let requires_dist = get_all_values("Requires-Dist") - .iter() - .map(|requires_dist| LenientRequirement::from_str(requires_dist).map(Requirement::from)) + .map(|requires_dist| { + LenientRequirement::from_str(&requires_dist).map(Requirement::from) + }) .collect::, _>>()?; - let provides_dist = get_all_values("Provides-Dist") - .into_iter() - .map(PackageName::new) - .collect::, _>>()?; - let obsoletes_dist = get_all_values("Obsoletes-Dist"); - let maintainer = get_first_value("Maintainer"); - let maintainer_email = get_first_value("Maintainer-email"); let requires_python = get_first_value("Requires-Python") .map(|requires_python| { LenientVersionSpecifiers::from_str(&requires_python).map(VersionSpecifiers::from) }) .transpose()?; - let requires_external = get_all_values("Requires-External"); - let project_urls = get_all_values("Project-URL") - .iter() - .map(|name_value| match name_value.split_once(',') { - None => Err(Error::InvalidProjectUrl(name_value.clone())), - Some((name, value)) => Ok((name.to_string(), value.trim().to_string())), - }) - .collect::>()?; let provides_extras = get_all_values("Provides-Extra") - .into_iter() .map(ExtraName::new) .collect::, _>>()?; - let description_content_type = get_first_value("Description-Content-Type"); + Ok(Metadata21 { metadata_version, name, version, - platforms, - supported_platforms, - summary, - description, - description_content_type, - keywords, - home_page, - download_url, - author, - author_email, - maintainer, - maintainer_email, - license, - classifiers, requires_dist, - provides_dist, - obsoletes_dist, requires_python, - requires_external, - project_urls, provides_extras, }) }