use std::collections::{BTreeMap, BTreeSet};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::config::DeployConfig;
use crate::error::ConfigError;
use crate::file::FileEntry;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Manifest {
#[serde(default = "crate::schema_version")]
pub version: u32,
pub files: BTreeMap<String, FileEntry>,
#[serde(default)]
pub config: DeployConfig,
}
impl Default for Manifest {
fn default() -> Self {
Self {
version: crate::SCHEMA_VERSION,
files: BTreeMap::new(),
config: DeployConfig::default(),
}
}
}
impl Manifest {
pub fn to_bytes(&self) -> Result<Vec<u8>, ConfigError> {
serde_json::to_vec(self).map_err(|err| ConfigError::parse(err.to_string()))
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ConfigError> {
serde_json::from_slice(bytes).map_err(|err| ConfigError::parse(err.to_string()))
}
pub fn id(&self) -> Result<String, ConfigError> {
Ok(sha256_hex(&self.to_bytes()?))
}
pub fn blob_hashes(&self) -> BTreeSet<String> {
let mut hashes = BTreeSet::new();
for entry in self.files.values() {
hashes.insert(entry.hash.clone());
for variant in entry.variants.values() {
hashes.insert(variant.hash.clone());
}
}
hashes
}
}
pub fn sha256_hex(data: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(data);
hex::encode(hasher.finalize())
}