diff options
Diffstat (limited to 'vendor/gix-ref/src/transaction/mod.rs')
-rw-r--r-- | vendor/gix-ref/src/transaction/mod.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/vendor/gix-ref/src/transaction/mod.rs b/vendor/gix-ref/src/transaction/mod.rs new file mode 100644 index 000000000..d13ff2e70 --- /dev/null +++ b/vendor/gix-ref/src/transaction/mod.rs @@ -0,0 +1,143 @@ +//! **Transactions** are the only way make changes to the ref store in order to increase the chance of consistency in a multi-threaded +//! environment. +//! +//! Transactions currently allow to… +//! +//! * create or update reference +//! * delete references +//! +//! The following guarantees are made: +//! +//! * transactions are prepared which is when other writers are prevented from changing them +//! - errors during preparations will cause a perfect rollback +//! * prepared transactions are committed to finalize the change +//! - errors when committing while leave the ref store in an inconsistent, but operational state. +use gix_object::bstr::BString; + +use crate::{FullName, Target}; + +/// A change to the reflog. +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] +pub struct LogChange { + /// How to treat the reference log. + pub mode: RefLog, + /// If set, create a reflog even though it would otherwise not be the case as prohibited by general rules. + /// Note that ref-log writing might be prohibited in the entire repository which is when this flag has no effect either. + pub force_create_reflog: bool, + /// The message to put into the reference log. It must be a single line, hence newlines are forbidden. + /// The string can be empty to indicate there should be no message at all. + pub message: BString, +} + +impl Default for LogChange { + fn default() -> Self { + LogChange { + mode: RefLog::AndReference, + force_create_reflog: false, + message: Default::default(), + } + } +} + +/// The desired value of an updated value +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] +pub enum PreviousValue { + /// No requirements are made towards the current value, and the new value is set unconditionally. + Any, + /// The reference must exist and may have any value. + MustExist, + /// Create the ref only, hence the reference must not exist. + MustNotExist, + /// The ref _must_ exist and have the given value. + MustExistAndMatch(Target), + /// The ref _may_ exist and have the given value, or may not exist at all. + ExistingMustMatch(Target), +} + +/// A description of an edit to perform. +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] +pub enum Change { + /// If previous is not `None`, the ref must exist and its `oid` must agree with the `previous`, and + /// we function like `update`. + /// Otherwise it functions as `create-or-update`. + Update { + /// The desired change to the reference log. + log: LogChange, + /// The expected value already present in the reference. + /// If a ref was existing previously it will be overwritten at `MustExistAndMatch(actual_value)` for use after + /// the transaction was committed successfully. + expected: PreviousValue, + /// The new state of the reference, either for updating an existing one or creating a new one. + new: Target, + }, + /// Delete a reference and optionally check if `previous` is its content. + Delete { + /// The expected value of the reference, with the `MustNotExist` variant being invalid. + /// + /// If a previous ref existed, this value will be filled in automatically as `MustExistAndMatch(actual_value)` and + /// can be accessed if the transaction was committed successfully. + expected: PreviousValue, + /// How to treat the reference log during deletion. + log: RefLog, + }, +} + +impl Change { + /// Return references to values that are the new value after the change is applied, if this is an update. + pub fn new_value(&self) -> Option<crate::TargetRef<'_>> { + match self { + Change::Update { new, .. } => new.to_ref().into(), + Change::Delete { .. } => None, + } + } + + /// Return references to values that are in common between all variants and denote the previous observed value. + pub fn previous_value(&self) -> Option<crate::TargetRef<'_>> { + match self { + // TODO: use or-patterns once MRV is larger than 1.52 (and this is supported) + Change::Update { + expected: PreviousValue::MustExistAndMatch(previous), + .. + } + | Change::Update { + expected: PreviousValue::ExistingMustMatch(previous), + .. + } + | Change::Delete { + expected: PreviousValue::MustExistAndMatch(previous), + .. + } + | Change::Delete { + expected: PreviousValue::ExistingMustMatch(previous), + .. + } => previous, + _ => return None, + } + .to_ref() + .into() + } +} + +/// A reference that is to be changed +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] +pub struct RefEdit { + /// The change itself + pub change: Change, + /// The name of the reference to apply the change to + pub name: FullName, + /// If set, symbolic references identified by `name` will be dereferenced to have the `change` applied to their target. + /// This flag has no effect if the reference isn't symbolic. + pub deref: bool, +} + +/// The way to deal with the Reflog in deletions. +#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] +pub enum RefLog { + /// Delete or update the reference and the log + AndReference, + /// Delete or update only the reflog + Only, +} + +mod ext; +pub use ext::RefEditsExt; |