use crate::prelude::*;
use indexmap::IndexMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Meta {
pub version: String,
}
impl Default for Meta {
fn default() -> Self {
Self {
version: "1.0".into(),
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
enum RawDistInfoMetadata {
NoHashes(bool),
WithHashes(HashMap<String, String>),
}
#[derive(Debug, Clone, Deserialize, Default, PartialEq, Eq, Serialize)]
#[serde(from = "Option<RawDistInfoMetadata>")]
pub struct DistInfoMetadata {
pub available: bool,
pub hash: Option<ArtifactHash>,
}
impl From<Option<RawDistInfoMetadata>> for DistInfoMetadata {
fn from(maybe_raw: Option<RawDistInfoMetadata>) -> Self {
match maybe_raw {
None => Default::default(),
Some(raw) => match raw {
RawDistInfoMetadata::NoHashes(available) => Self {
available,
hash: None,
},
RawDistInfoMetadata::WithHashes(_) => {
Self {
available: true,
hash: None,
}
}
},
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
enum RawYanked {
NoReason(bool),
WithReason(String),
}
#[derive(Debug, Clone, Deserialize, Default, PartialEq, Eq, Serialize)]
#[serde(from = "RawYanked")]
pub struct Yanked {
pub yanked: bool,
pub reason: Option<String>,
}
impl From<RawYanked> for Yanked {
fn from(raw: RawYanked) -> Self {
match raw {
RawYanked::NoReason(yanked) => Self {
yanked,
reason: None,
},
RawYanked::WithReason(reason) => Self {
yanked: true,
reason: Some(reason),
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ArtifactInfo {
pub name: ArtifactName,
pub url: Url,
pub hash: Option<ArtifactHash>,
pub requires_python: Option<String>,
pub dist_info_metadata: DistInfoMetadata,
pub yanked: Yanked,
}
impl ArtifactInfo {
pub fn is<T: Artifact>(&self) -> bool {
self.name.inner_as::<T::Name>().is_some()
}
pub fn require_hash(&self) -> Result<&ArtifactHash> {
self.hash
.as_ref()
.ok_or_else(|| eyre!("artifact {} has no hash", self.name))
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct ProjectInfo {
pub meta: Meta,
pub artifacts: Vec<ArtifactInfo>,
}
pub fn pack_by_version(
pi: ProjectInfo,
map: &mut IndexMap<Version, Vec<ArtifactInfo>>,
) -> Result<()> {
if !pi.meta.version.starts_with("1.") {
bail!("unknown package index api version {}", pi.meta.version);
}
for ai in pi.artifacts.into_iter() {
let entry = map.entry(ai.name.version().clone());
entry.or_insert_with(Default::default).push(ai);
}
Ok(())
}