use std::collections::BTreeMap;
use std::path::PathBuf;
use multihash::Multihash;
use serde::de;
use serde::ser;
use serde::Deserialize;
use serde::Serialize;
use crate::lineage::status::UpstreamState;
use crate::uri::ManifestUri;
fn multihash_to_str<S: ser::Serializer>(
hash: &Multihash<256>,
serializer: S,
) -> Result<S::Ok, S::Error> {
let s = hex::encode(hash.to_bytes());
serializer.serialize_str(&s)
}
fn str_to_multihash<'de, D: de::Deserializer<'de>>(
deserializer: D,
) -> Result<Multihash<256>, D::Error> {
let s = String::deserialize(deserializer)?;
let bytes = hex::decode(s).map_err(de::Error::custom)?;
Multihash::from_bytes(&bytes).map_err(de::Error::custom)
}
#[derive(Default, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PathState {
pub timestamp: chrono::DateTime<chrono::Utc>,
#[serde(
serialize_with = "multihash_to_str",
deserialize_with = "str_to_multihash"
)]
pub hash: Multihash<256>,
}
pub type LineagePaths = BTreeMap<PathBuf, PathState>;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct CommitState {
pub timestamp: chrono::DateTime<chrono::Utc>,
pub hash: String, #[serde(default = "Vec::new")]
pub prev_hashes: Vec<String>, }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
pub struct PackageLineage {
pub commit: Option<CommitState>,
pub remote: ManifestUri,
pub base_hash: String,
pub latest_hash: String,
#[serde(default = "BTreeMap::new")]
pub paths: LineagePaths,
}
impl From<PackageLineage> for UpstreamState {
fn from(lineage: PackageLineage) -> Self {
let behind = lineage.base_hash != lineage.latest_hash;
let ahead = lineage.base_hash != lineage.current_hash();
match (ahead, behind) {
(false, false) => Self::UpToDate,
(false, true) => Self::Behind,
(true, false) => Self::Ahead,
(true, true) => Self::Diverged,
}
}
}
impl PackageLineage {
pub fn from_remote(remote: ManifestUri, latest_hash: String) -> Self {
Self {
base_hash: remote.hash.clone(),
remote,
latest_hash,
commit: None,
paths: BTreeMap::new(),
}
}
pub fn current_hash(&self) -> &str {
self.commit.as_ref().map_or(&self.remote.hash, |c| &c.hash)
}
pub fn update_latest(&mut self, manifest_uri: ManifestUri) {
let new_latest_hash = manifest_uri.hash;
self.latest_hash.clone_from(&new_latest_hash);
self.base_hash.clone_from(&new_latest_hash);
}
}
impl From<ManifestUri> for PackageLineage {
fn from(uri: ManifestUri) -> Self {
Self {
base_hash: uri.hash.clone(),
remote: uri.clone(),
latest_hash: uri.hash.clone(),
commit: None,
paths: BTreeMap::new(),
}
}
}