use crate::errors::{Error, Result};
use reqwest::Method;
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ManifestSchema2Spec {
#[serde(rename = "schemaVersion")]
schema_version: u16,
#[serde(rename = "mediaType")]
media_type: String,
config: Config,
layers: Vec<S2Layer>,
}
#[derive(Debug, Default)]
pub struct ManifestSchema2 {
pub manifest_spec: ManifestSchema2Spec,
pub config_blob: ConfigBlob,
}
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
pub struct Config {
#[serde(rename = "mediaType")]
pub media_type: String,
pub size: u64,
pub digest: String,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ConfigBlob {
architecture: String,
}
#[derive(Debug, Default, Deserialize, Serialize)]
struct S2Layer {
#[serde(rename = "mediaType")]
media_type: String,
size: u64,
digest: String,
urls: Option<Vec<String>>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ManifestList {
#[serde(rename = "schemaVersion")]
schema_version: u16,
#[serde(rename = "mediaType")]
media_type: String,
pub manifests: Vec<ManifestObj>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ManifestObj {
#[serde(rename = "mediaType")]
media_type: String,
size: u64,
pub digest: String,
pub platform: Platform,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Platform {
pub architecture: String,
pub os: String,
#[serde(rename = "os.version")]
pub os_version: Option<String>,
#[serde(rename = "os.features")]
pub os_features: Option<Vec<String>>,
pub variant: Option<String>,
pub features: Option<Vec<String>>,
}
impl ManifestSchema2Spec {
pub fn config(&self) -> &Config {
&self.config
}
pub(crate) async fn fetch_config_blob(
self,
client: crate::v2::Client,
repo: String,
) -> Result<ManifestSchema2> {
let url = {
let ep = format!(
"{}/v2/{}/blobs/{}",
client.base_url.clone(),
repo,
self.config.digest
);
reqwest::Url::parse(&ep)?
};
let r = client
.build_reqwest(Method::GET, url.clone())
.send()
.await?;
let status = r.status();
trace!("GET {:?}: {}", url, &status);
if !status.is_success() {
return Err(Error::UnexpectedHttpStatus(status));
}
let config_blob = r.json::<ConfigBlob>().await?;
Ok(ManifestSchema2 {
manifest_spec: self,
config_blob,
})
}
}
impl ManifestSchema2 {
pub fn get_layers(&self) -> Vec<String> {
self.manifest_spec
.layers
.iter()
.map(|l| l.digest.clone())
.collect()
}
pub fn architecture(&self) -> String {
self.config_blob.architecture.to_owned()
}
}