mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 10:58:28 +00:00
Encapsulate header parsing for metadata files (#2295)
This commit is contained in:
parent
26f6919465
commit
8a807094e9
1 changed files with 39 additions and 21 deletions
|
@ -76,24 +76,7 @@ pub enum Error {
|
||||||
impl Metadata21 {
|
impl Metadata21 {
|
||||||
/// Parse distribution metadata from metadata bytes
|
/// Parse distribution metadata from metadata bytes
|
||||||
pub fn parse(content: &[u8]) -> Result<Self, Error> {
|
pub fn parse(content: &[u8]) -> Result<Self, Error> {
|
||||||
let (headers, _) = mailparse::parse_headers(content)?;
|
let headers = Headers::parse(content)?;
|
||||||
|
|
||||||
let get_first_value = |name| {
|
|
||||||
headers.get_first_header(name).and_then(|header| {
|
|
||||||
let value = header.get_value();
|
|
||||||
if value == "UNKNOWN" {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
let get_all_values = |name| {
|
|
||||||
headers
|
|
||||||
.get_all_values(name)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|value| value != "UNKNOWN")
|
|
||||||
};
|
|
||||||
|
|
||||||
let metadata_version = headers
|
let metadata_version = headers
|
||||||
.get_first_value("Metadata-Version")
|
.get_first_value("Metadata-Version")
|
||||||
|
@ -109,17 +92,20 @@ impl Metadata21 {
|
||||||
.ok_or(Error::FieldNotFound("Version"))?,
|
.ok_or(Error::FieldNotFound("Version"))?,
|
||||||
)
|
)
|
||||||
.map_err(Error::Pep440VersionError)?;
|
.map_err(Error::Pep440VersionError)?;
|
||||||
let requires_dist = get_all_values("Requires-Dist")
|
let requires_dist = headers
|
||||||
|
.get_all_values("Requires-Dist")
|
||||||
.map(|requires_dist| {
|
.map(|requires_dist| {
|
||||||
LenientRequirement::from_str(&requires_dist).map(Requirement::from)
|
LenientRequirement::from_str(&requires_dist).map(Requirement::from)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let requires_python = get_first_value("Requires-Python")
|
let requires_python = headers
|
||||||
|
.get_first_value("Requires-Python")
|
||||||
.map(|requires_python| {
|
.map(|requires_python| {
|
||||||
LenientVersionSpecifiers::from_str(&requires_python).map(VersionSpecifiers::from)
|
LenientVersionSpecifiers::from_str(&requires_python).map(VersionSpecifiers::from)
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
let provides_extras = get_all_values("Provides-Extra")
|
let provides_extras = headers
|
||||||
|
.get_all_values("Provides-Extra")
|
||||||
.filter_map(|provides_extra| match ExtraName::new(provides_extra) {
|
.filter_map(|provides_extra| match ExtraName::new(provides_extra) {
|
||||||
Ok(extra_name) => Some(extra_name),
|
Ok(extra_name) => Some(extra_name),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -147,6 +133,38 @@ impl FromStr for Metadata21 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The headers of a distribution metadata file.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Headers<'a>(Vec<mailparse::MailHeader<'a>>);
|
||||||
|
|
||||||
|
impl<'a> Headers<'a> {
|
||||||
|
/// Parse the headers from the given metadata file content.
|
||||||
|
fn parse(content: &'a [u8]) -> Result<Self, MailParseError> {
|
||||||
|
let (headers, _) = mailparse::parse_headers(content)?;
|
||||||
|
Ok(Self(headers))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the first value associated with the header with the given name.
|
||||||
|
fn get_first_value(&self, name: &str) -> Option<String> {
|
||||||
|
self.0.get_first_header(name).and_then(|header| {
|
||||||
|
let value = header.get_value();
|
||||||
|
if value == "UNKNOWN" {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return all values associated with the header with the given name.
|
||||||
|
fn get_all_values(&self, name: &str) -> impl Iterator<Item = String> {
|
||||||
|
self.0
|
||||||
|
.get_all_values(name)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|value| value != "UNKNOWN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue