From a483cc97d56a770c4ccf91dfccf790a8c2d0c9fa Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Wed, 29 Mar 2023 13:20:08 +0200 Subject: core: version each metadata type separately It turns out to be preferable to be able to break one type without affecting the other. So instead of the global SpecVersion, use a separate FmtVersion for each type. For compatibility, keep supporting spec_version fields (until next major bump of the respective types' version). Signed-off-by: Kim Altintop --- src/cmd/drop.rs | 2 +- src/cmd/drop/init.rs | 2 +- src/cmd/id.rs | 2 +- src/cmd/id/init.rs | 2 +- src/lib.rs | 2 -- src/metadata.rs | 26 ++++++----------- src/metadata/drop.rs | 54 ++++++++++++++++++++++++++++++++---- src/metadata/identity.rs | 52 +++++++++++++++++++++++++++++++--- src/metadata/mirrors.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++---- 9 files changed, 175 insertions(+), 39 deletions(-) diff --git a/src/cmd/drop.rs b/src/cmd/drop.rs index 208dbd6..8051253 100644 --- a/src/cmd/drop.rs +++ b/src/cmd/drop.rs @@ -195,7 +195,7 @@ impl TryFrom for metadata::Drop { } Ok(Self { - spec_version: crate::SPEC_VERSION, + fmt_version: Default::default(), description, prev: None, roles, diff --git a/src/cmd/drop/init.rs b/src/cmd/drop/init.rs index b843255..a1c5025 100644 --- a/src/cmd/drop/init.rs +++ b/src/cmd/drop/init.rs @@ -121,7 +121,7 @@ pub fn init(args: Init) -> cmd::Result { let default_branch = cfg::git::default_branch(&cfg)?; metadata::Drop { - spec_version: crate::SPEC_VERSION, + fmt_version: Default::default(), description: args.description, prev: None, custom: Default::default(), diff --git a/src/cmd/id.rs b/src/cmd/id.rs index 7504489..57e79b0 100644 --- a/src/cmd/id.rs +++ b/src/cmd/id.rs @@ -176,7 +176,7 @@ impl TryFrom for metadata::Identity { ensure!(!keys.is_empty(), "keys cannot be empty"); Ok(Self { - spec_version: crate::SPEC_VERSION, + fmt_version: Default::default(), prev: None, keys, threshold, diff --git a/src/cmd/id/init.rs b/src/cmd/id/init.rs index a0ed119..35d3bb8 100644 --- a/src/cmd/id/init.rs +++ b/src/cmd/id/init.rs @@ -148,7 +148,7 @@ pub fn init(args: Init) -> cmd::Result { let meta = { let id = metadata::Identity { - spec_version: crate::SPEC_VERSION, + fmt_version: Default::default(), prev: None, keys, threshold, diff --git a/src/lib.rs b/src/lib.rs index 789f99f..c8c8887 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,8 +16,6 @@ mod serde; mod ssh; mod str; -pub const SPEC_VERSION: metadata::SpecVersion = metadata::SpecVersion::current(); - pub mod cmd; pub use cmd::{ ui::Output, diff --git a/src/metadata.rs b/src/metadata.rs index 9caee96..2da268f 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -56,13 +56,9 @@ pub use identity::{ }; #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] -pub struct SpecVersion(SemVer); - -impl SpecVersion { - pub const fn current() -> Self { - Self::new(0, 1, 0) - } +pub struct FmtVersion(SemVer); +impl FmtVersion { const fn new(major: u32, minor: u32, patch: u32) -> Self { Self(SemVer { major, @@ -92,19 +88,13 @@ impl SpecVersion { } } -impl Default for SpecVersion { - fn default() -> Self { - Self::current() - } -} - -impl fmt::Display for SpecVersion { +impl fmt::Display for FmtVersion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } -impl FromStr for SpecVersion { +impl FromStr for FmtVersion { type Err = ::Err; fn from_str(s: &str) -> Result { @@ -112,7 +102,7 @@ impl FromStr for SpecVersion { } } -impl<'a> TryFrom<&'a str> for SpecVersion { +impl<'a> TryFrom<&'a str> for FmtVersion { type Error = >::Error; fn try_from(value: &str) -> Result { @@ -120,13 +110,13 @@ impl<'a> TryFrom<&'a str> for SpecVersion { } } -impl AsRef for SpecVersion { +impl AsRef for FmtVersion { fn as_ref(&self) -> &SemVer { &self.0 } } -impl serde::Serialize for SpecVersion { +impl serde::Serialize for FmtVersion { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -135,7 +125,7 @@ impl serde::Serialize for SpecVersion { } } -impl<'de> serde::Deserialize<'de> for SpecVersion { +impl<'de> serde::Deserialize<'de> for FmtVersion { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, diff --git a/src/metadata/drop.rs b/src/metadata/drop.rs index d231712..1341f68 100644 --- a/src/metadata/drop.rs +++ b/src/metadata/drop.rs @@ -10,6 +10,7 @@ use std::{ }, io, num::NonZeroUsize, + ops::Deref, }; use log::warn; @@ -32,7 +33,6 @@ use super::{ Mirrors, Signature, Signed, - SpecVersion, }; use crate::{ git::Refname, @@ -40,6 +40,25 @@ use crate::{ str::Varchar, }; +pub const FMT_VERSION: FmtVersion = FmtVersion(super::FmtVersion::new(0, 2, 0)); + +#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +pub struct FmtVersion(super::FmtVersion); + +impl Deref for FmtVersion { + type Target = super::FmtVersion; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for FmtVersion { + fn default() -> Self { + FMT_VERSION + } +} + #[derive(Clone, serde::Serialize, serde::Deserialize)] pub struct Roles { pub root: Role, @@ -83,9 +102,10 @@ pub struct Annotated { pub type Verified = super::Verified; -#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[derive(Clone, serde::Deserialize)] pub struct Drop { - pub spec_version: SpecVersion, + #[serde(alias = "spec_version")] + pub fmt_version: FmtVersion, #[serde(default = "Description::new")] pub description: Description, pub prev: Option, @@ -121,7 +141,7 @@ impl Drop { { use error::Verification::*; - if !crate::SPEC_VERSION.is_compatible(&self.spec_version) { + if !FMT_VERSION.is_compatible(&self.fmt_version) { return Err(IncompatibleSpecVersion); } @@ -153,7 +173,7 @@ impl Drop { return Err(Expired); } } - if !crate::SPEC_VERSION.is_compatible(&mirrors.signed.spec_version) { + if !FMT_VERSION.is_compatible(&mirrors.signed.fmt_version) { return Err(IncompatibleSpecVersion); } @@ -177,7 +197,7 @@ impl Drop { return Err(Expired); } } - if !crate::SPEC_VERSION.is_compatible(&alt.signed.spec_version) { + if !FMT_VERSION.is_compatible(&alt.signed.fmt_version) { return Err(IncompatibleSpecVersion); } @@ -203,6 +223,28 @@ impl<'a> From<&'a Drop> for Cow<'a, Drop> { } } +impl serde::Serialize for Drop { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + + let mut s = serializer.serialize_struct("Drop", 5)?; + let version_field = if self.fmt_version < FMT_VERSION { + "spec_version" + } else { + "fmt_version" + }; + s.serialize_field(version_field, &self.fmt_version)?; + s.serialize_field("description", &self.description)?; + s.serialize_field("prev", &self.prev)?; + s.serialize_field("roles", &self.roles)?; + s.serialize_field("custom", &self.custom)?; + s.end() + } +} + mod verify { use super::*; diff --git a/src/metadata/identity.rs b/src/metadata/identity.rs index 8071e84..15967c4 100644 --- a/src/metadata/identity.rs +++ b/src/metadata/identity.rs @@ -11,6 +11,7 @@ use std::{ io, marker::PhantomData, num::NonZeroUsize, + ops::Deref, path::PathBuf, str::FromStr, }; @@ -46,7 +47,6 @@ use super::{ Metadata, Signature, Signed, - SpecVersion, }; use crate::{ json::{ @@ -56,6 +56,25 @@ use crate::{ metadata::git::find_parent, }; +pub const FMT_VERSION: FmtVersion = FmtVersion(super::FmtVersion::new(0, 2, 0)); + +#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +pub struct FmtVersion(super::FmtVersion); + +impl Deref for FmtVersion { + type Target = super::FmtVersion; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for FmtVersion { + fn default() -> Self { + FMT_VERSION + } +} + #[derive( Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash, serde::Serialize, serde::Deserialize, )] @@ -135,9 +154,10 @@ impl AsRef for Verified { } } -#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[derive(Clone, serde::Deserialize)] pub struct Identity { - pub spec_version: SpecVersion, + #[serde(alias = "spec_version")] + pub fmt_version: FmtVersion, pub prev: Option, pub keys: KeySet<'static>, pub threshold: NonZeroUsize, @@ -188,7 +208,7 @@ impl Identity { { use error::Verification::IncompatibleSpecVersion; - if !crate::SPEC_VERSION.is_compatible(&self.spec_version) { + if !FMT_VERSION.is_compatible(&self.fmt_version) { return Err(IncompatibleSpecVersion); } @@ -259,6 +279,30 @@ impl<'a> From<&'a Identity> for Cow<'a, Identity> { } } +impl serde::Serialize for Identity { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + + let mut s = serializer.serialize_struct("Identity", 7)?; + let version_field = if self.fmt_version < FMT_VERSION { + "spec_version" + } else { + "fmt_version" + }; + s.serialize_field(version_field, &self.fmt_version)?; + s.serialize_field("prev", &self.prev)?; + s.serialize_field("keys", &self.keys)?; + s.serialize_field("threshold", &self.threshold)?; + s.serialize_field("mirrors", &self.mirrors)?; + s.serialize_field("expires", &self.expires)?; + s.serialize_field("custom", &self.custom)?; + s.end() + } +} + fn verify_signatures<'a, S>( payload: &[u8], threshold: NonZeroUsize, diff --git a/src/metadata/mirrors.rs b/src/metadata/mirrors.rs index 9124dd3..eb437c9 100644 --- a/src/metadata/mirrors.rs +++ b/src/metadata/mirrors.rs @@ -4,6 +4,7 @@ use std::{ borrow::Cow, collections::BTreeSet, + ops::Deref, }; use url::Url; @@ -12,13 +13,31 @@ use super::{ Custom, DateTime, Metadata, - SpecVersion, }; use crate::{ json::canonical, str::Varchar, }; +pub const FMT_VERSION: FmtVersion = FmtVersion(super::FmtVersion::new(0, 2, 0)); + +#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +pub struct FmtVersion(super::FmtVersion); + +impl Deref for FmtVersion { + type Target = super::FmtVersion; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for FmtVersion { + fn default() -> Self { + FMT_VERSION + } +} + #[derive(Clone, serde::Serialize, serde::Deserialize)] pub struct Mirror { pub url: Url, @@ -42,9 +61,10 @@ pub enum Kind { Unknown(Varchar), } -#[derive(Clone, Default, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Default, serde::Deserialize)] pub struct Mirrors { - pub spec_version: SpecVersion, + #[serde(alias = "spec_version")] + pub fmt_version: FmtVersion, pub mirrors: Vec, pub expires: Option, } @@ -67,9 +87,30 @@ impl<'a> From<&'a Mirrors> for Cow<'a, Mirrors> { } } -#[derive(Clone, Default, serde::Serialize, serde::Deserialize)] +impl serde::Serialize for Mirrors { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + + let mut s = serializer.serialize_struct("Mirrors", 3)?; + let version_field = if self.fmt_version < FMT_VERSION { + "spec_version" + } else { + "fmt_version" + }; + s.serialize_field(version_field, &self.fmt_version)?; + s.serialize_field("mirrors", &self.mirrors)?; + s.serialize_field("expires", &self.expires)?; + s.end() + } +} + +#[derive(Clone, Default, serde::Deserialize)] pub struct Alternates { - pub spec_version: SpecVersion, + #[serde(alias = "spec_version")] + pub fmt_version: FmtVersion, pub alternates: BTreeSet, #[serde(default)] pub custom: Custom, @@ -93,3 +134,24 @@ impl<'a> From<&'a Alternates> for Cow<'a, Alternates> { Self::Borrowed(a) } } + +impl serde::Serialize for Alternates { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + + let mut s = serializer.serialize_struct("Alternates", 4)?; + let version_field = if self.fmt_version < FMT_VERSION { + "spec_version" + } else { + "fmt_version" + }; + s.serialize_field(version_field, &self.fmt_version)?; + s.serialize_field("alternates", &self.alternates)?; + s.serialize_field("custom", &self.custom)?; + s.serialize_field("expires", &self.expires)?; + s.end() + } +} -- cgit v1.2.3