use radicle::git; use radicle::git::canonical; use radicle::git::canonical::QuorumWithConvergence; use radicle::git::canonical::effects; use radicle::git::canonical::error::QuorumError; use radicle::prelude::Did; /// Validates a vote to update a canonical reference during push. pub(crate) struct Canonical<'a, 'b, 'r, R> { canonical: canonical::CanonicalWithConvergence<'a, 'b, 'r, R>, } impl<'a, 'b, 'r, R> Canonical<'a, 'b, 'r, R> where R: effects::Ancestry + effects::FindMergeBase + effects::FindObjects, { pub(super) fn new( me: Did, object: canonical::Object, canonical: canonical::Canonical<'a, 'b, 'r, R, canonical::Initial>, ) -> Result { let canonical = canonical.find_objects()?; Ok(Self { canonical: canonical.with_convergence(me, object), }) } /// Calculates the quorum of the [`git::canonical::Canonical`] provided. /// /// In some cases, it ensures that the head commit is attempting to converge /// with the set of commits of the other [`Did`]s. /// /// If a quorum is found, then it is also ensured that the new head commit /// is a descendant of the current canonical commit; otherwise, the commits /// are considered diverging. /// /// # Errors /// /// Ensures that the commits of the other [`Did`]s are in the working /// copy, and that checks that any two commits are related in the graph. /// /// Ensures that the new head and the canonical commit do not diverge. pub(super) fn quorum( self, ) -> Result<(git::fmt::Qualified<'a>, canonical::Object), QuorumError> { self.canonical .quorum() .map(|QuorumWithConvergence { quorum, .. }| (quorum.refname, quorum.object)) } } pub(crate) mod io { use radicle::git::canonical::error::QuorumError; use crate::push::error; use crate::warn; /// Handle recoverable errors, printing relevant information to the /// terminal. Otherwise, convert the error into an unrecoverable error /// [`error::CanonicalUnrecoverable`]. pub(crate) fn handle_error(e: QuorumError) -> Result<(), error::CanonicalUnrecoverable> { match e { QuorumError::Convergence(err) => Err(err.into()), QuorumError::MergeBase(err) => Err(err.into()), e @ QuorumError::DivergingCommits { .. } => { warn(e.to_string()); warn("it is recommended to find a commit to agree upon"); Ok(()) } e @ QuorumError::DivergingTags { .. } => { warn(e.to_string()); warn("it is recommended to find a tag to agree upon"); Ok(()) } e @ QuorumError::DifferentTypes { .. } => { warn(e.to_string()); warn( "it is recommended to find an object type (either commit or tag) to agree upon", ); Ok(()) } e @ QuorumError::NoCandidates { .. } => { warn(e.to_string()); warn("it is recommended to find an object (either commit or tag) to agree upon"); Ok(()) } } } }