radicle_fetch/git/refs/update.rs
1//! The set of types that describe performing updates to a Git
2//! repository.
3//!
4//! An [`Update`] describes a single update that can made to a Git
5//! repository. **Note** that it currently does not support symbolic
6//! references.
7//!
8//! A group of `Update`s is described by [`Updates`] which groups
9//! those updates by each peer's namespace, i.e. their [`PublicKey`].
10//!
11//! When an `Update` is successful the corresponding [`Updated`] is
12//! expected to be produced.
13//!
14//! The final result of applying a set of [`Updates`] is captured in
15//! the [`Applied`] type, which contains any rejected, but non-fatal,
16//! [`Update`]s and successful [`Updated`] values.
17
18use std::collections::BTreeMap;
19
20use either::Either;
21use radicle::git::{Namespaced, Oid, Qualified};
22use radicle::prelude::PublicKey;
23
24pub use radicle::storage::RefUpdate;
25
26/// The set of applied changes from a reference store update.
27#[derive(Debug, Default)]
28pub struct Applied<'a> {
29 /// Set of rejected updates if they did not meet the update
30 /// requirements, e.g. concurrent change to previous object id,
31 /// broke fast-forward policy, etc.
32 pub rejected: Vec<Update<'a>>,
33 /// Set of successfully updated references.
34 pub updated: Vec<RefUpdate>,
35}
36
37impl Applied<'_> {
38 pub fn append(&mut self, other: &mut Self) {
39 self.rejected.append(&mut other.rejected);
40 self.updated.append(&mut other.updated);
41 }
42}
43
44/// A set of [`Update`]s that are grouped by which namespace they are
45/// affecting.
46#[derive(Clone, Default, Debug)]
47pub struct Updates<'a> {
48 pub tips: BTreeMap<PublicKey, Vec<Update<'a>>>,
49}
50
51impl<'a> Updates<'a> {
52 pub fn build(updates: impl IntoIterator<Item = (PublicKey, Update<'a>)>) -> Self {
53 let tips = updates.into_iter().fold(
54 BTreeMap::<_, Vec<Update<'a>>>::new(),
55 |mut tips, (remote, up)| {
56 tips.entry(remote)
57 .and_modify(|ups| ups.push(up.clone()))
58 .or_insert(vec![up]);
59 tips
60 },
61 );
62 Self { tips }
63 }
64
65 pub fn add(&mut self, remote: PublicKey, up: Update<'a>) {
66 self.tips
67 .entry(remote)
68 .and_modify(|ups| ups.push(up.clone()))
69 .or_insert(vec![up]);
70 }
71
72 pub fn append(&mut self, remote: PublicKey, mut new: Vec<Update<'a>>) {
73 self.tips
74 .entry(remote)
75 .and_modify(|ups| ups.append(&mut new))
76 .or_insert(new);
77 }
78}
79
80/// The policy to follow when an [`Update::Direct`] is not a
81/// fast-forward.
82#[derive(Clone, Copy, Debug)]
83pub enum Policy {
84 /// Abort the entire transaction.
85 Abort,
86 /// Reject this update, but continue the transaction.
87 Reject,
88 /// Allow the update.
89 Allow,
90}
91
92/// An update that can be applied to a Git repository.
93#[derive(Clone, Debug)]
94pub enum Update<'a> {
95 /// Update a direct reference, i.e. a reference that points to an
96 /// object.
97 Direct {
98 /// The name of the reference that is being updated.
99 name: Namespaced<'a>,
100 /// The resulting target of the reference that is being
101 /// updated.
102 target: Oid,
103 /// Policy to apply when an [`Update`] would not apply as a
104 /// fast-forward.
105 no_ff: Policy,
106 },
107 /// Delete a reference.
108 Prune {
109 /// The name of the reference that is being deleted.
110 name: Namespaced<'a>,
111 /// The previous value of the reference.
112 ///
113 /// It can either be a direct reference pointing to an
114 /// [`Oid`], or a symbolic reference pointing to a
115 /// [`Qualified`] reference name.
116 prev: Either<Oid, Qualified<'a>>,
117 },
118}
119
120impl<'a> Update<'a> {
121 pub fn refname(&self) -> &Namespaced<'a> {
122 match self {
123 Update::Direct { name, .. } => name,
124 Update::Prune { name, .. } => name,
125 }
126 }
127
128 pub fn into_owned<'b>(self) -> Update<'b> {
129 match self {
130 Self::Direct {
131 name,
132 target,
133 no_ff,
134 } => Update::Direct {
135 name: name.into_owned(),
136 target,
137 no_ff,
138 },
139 Self::Prune { name, prev } => Update::Prune {
140 name: name.into_owned(),
141 prev: prev.map_right(|q| q.into_owned()),
142 },
143 }
144 }
145}