use serde::{Deserialize, Serialize};
use snafu::ResultExt;
use crate::image::Image;
use crate::index::Index;
use crate::models::MediaType;
use crate::uri::Uri;
use crate::{Result, error};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Manifest {
Index(Index),
Image(Image),
}
impl Manifest {
pub async fn fetch(uri: &Uri) -> Result<Self> {
let value = uri
.registry()
.fetch_manifest_value(uri.repository(), uri.reference().to_string().as_str())
.await?;
let media_type: Option<MediaType> = value
.get("mediaType")
.and_then(|v| serde_json::from_value(v.clone()).ok());
match media_type {
Some(MediaType::ImageIndex) | Some(MediaType::DockerManifestList) => {
let index = serde_json::from_value(value).context(error::BodyDeserializeSnafu)?;
Ok(Manifest::Index(index))
}
Some(MediaType::Manifest) | Some(MediaType::DockerManifest) => {
let image = serde_json::from_value(value).context(error::BodyDeserializeSnafu)?;
Ok(Manifest::Image(image))
}
_ => {
if value.get("manifests").is_some() {
let index =
serde_json::from_value(value).context(error::BodyDeserializeSnafu)?;
Ok(Manifest::Index(index))
} else {
let image =
serde_json::from_value(value).context(error::BodyDeserializeSnafu)?;
Ok(Manifest::Image(image))
}
}
}
}
pub fn media_type(&self) -> &MediaType {
match self {
Manifest::Index(i) => i.media_type(),
Manifest::Image(i) => i.media_type(),
}
}
}