gix_ref/transaction/
mod.rs

1//! **Transactions** are the only way make changes to the ref store in order to increase the chance of consistency in a multi-threaded
2//! environment.
3//!
4//! Transactions currently allow to…
5//!
6//! * create or update reference
7//! * delete references
8//!
9//! The following guarantees are made:
10//!
11//! * transactions are prepared which is when other writers are prevented from changing them
12//!   - errors during preparations will cause a perfect rollback
13//! * prepared transactions are committed to finalize the change
14//!   - errors when committing while leave the ref store in an inconsistent, but operational state.
15use gix_object::bstr::BString;
16
17use crate::{FullName, Target};
18
19/// A change to the reflog.
20#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
21pub struct LogChange {
22    /// How to treat the reference log.
23    pub mode: RefLog,
24    /// If set, create a reflog even though it would otherwise not be the case as prohibited by general rules.
25    /// Note that ref-log writing might be prohibited in the entire repository which is when this flag has no effect either.
26    pub force_create_reflog: bool,
27    /// The message to put into the reference log. It must be a single line, hence newlines are forbidden.
28    /// The string can be empty to indicate there should be no message at all.
29    pub message: BString,
30}
31
32impl Default for LogChange {
33    fn default() -> Self {
34        LogChange {
35            mode: RefLog::AndReference,
36            force_create_reflog: false,
37            message: Default::default(),
38        }
39    }
40}
41
42/// The desired value of an updated value
43#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
44pub enum PreviousValue {
45    /// No requirements are made towards the current value, and the new value is set unconditionally.
46    Any,
47    /// The reference must exist and may have any value.
48    MustExist,
49    /// Create the ref only, hence the reference must not exist.
50    MustNotExist,
51    /// The ref _must_ exist and have the given value.
52    MustExistAndMatch(Target),
53    /// The ref _may_ exist and have the given value, or may not exist at all.
54    ExistingMustMatch(Target),
55}
56
57/// A description of an edit to perform.
58#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
59pub enum Change {
60    /// If previous is not `None`, the ref must exist and its `oid` must agree with the `previous`, and
61    /// we function like `update`.
62    /// Otherwise it functions as `create-or-update`.
63    Update {
64        /// The desired change to the reference log.
65        log: LogChange,
66        /// The expected value already present in the reference.
67        /// If a ref was existing previously this field will be overwritten with `MustExistAndMatch(actual_value)` for use after
68        /// the transaction was committed successfully.
69        expected: PreviousValue,
70        /// The new state of the reference, either for updating an existing one or creating a new one.
71        new: Target,
72    },
73    /// Delete a reference and optionally check if `previous` is its content.
74    Delete {
75        /// The expected value of the reference, with the `MustNotExist` variant being invalid.
76        ///
77        /// If a previous ref existed, this value will be filled in automatically as `MustExistAndMatch(actual_value)` and
78        /// can be accessed if the transaction was committed successfully.
79        expected: PreviousValue,
80        /// How to treat the reference log during deletion.
81        log: RefLog,
82    },
83}
84
85impl Change {
86    /// Return references to values that are the new value after the change is applied, if this is an update.
87    pub fn new_value(&self) -> Option<crate::TargetRef<'_>> {
88        match self {
89            Change::Update { new, .. } => new.to_ref().into(),
90            Change::Delete { .. } => None,
91        }
92    }
93
94    /// Return references to values that are in common between all variants and denote the previous observed value.
95    pub fn previous_value(&self) -> Option<crate::TargetRef<'_>> {
96        match self {
97            Change::Update {
98                expected: PreviousValue::MustExistAndMatch(previous) | PreviousValue::ExistingMustMatch(previous),
99                ..
100            }
101            | Change::Delete {
102                expected: PreviousValue::MustExistAndMatch(previous) | PreviousValue::ExistingMustMatch(previous),
103                ..
104            } => previous,
105            _ => return None,
106        }
107        .to_ref()
108        .into()
109    }
110}
111
112/// A reference that is to be changed
113#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
114pub struct RefEdit {
115    /// The change itself
116    pub change: Change,
117    /// The name of the reference to apply the change to
118    pub name: FullName,
119    /// If set, symbolic references  identified by `name`  will be dereferenced to have the `change` applied to their target.
120    /// This flag has no effect if the reference isn't symbolic.
121    pub deref: bool,
122}
123
124/// The way to deal with the Reflog in deletions.
125#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
126pub enum RefLog {
127    /// Delete or update the reference and the log
128    AndReference,
129    /// Delete or update only the reflog
130    Only,
131}
132
133mod ext;
134pub use ext::RefEditsExt;