git_ref/store/file/transaction/
mod.rs

1use std::fmt::Formatter;
2
3use git_hash::ObjectId;
4use git_object::bstr::BString;
5
6use crate::{
7    store_impl::{file, file::Transaction},
8    transaction::RefEdit,
9};
10
11/// A function receiving an object id to resolve, returning its decompressed bytes,
12/// used to obtain the peeled object ids for storage in packed-refs files.
13///
14/// Resolution means to follow tag objects until the end of the chain.
15pub type FindObjectFn<'a> = dyn FnMut(
16        git_hash::ObjectId,
17        &mut Vec<u8>,
18    ) -> Result<Option<git_object::Kind>, Box<dyn std::error::Error + Send + Sync + 'static>>
19    + 'a;
20
21/// How to handle packed refs during a transaction
22pub enum PackedRefs<'a> {
23    /// Only propagate deletions of references. This is the default
24    DeletionsOnly,
25    /// Propagate deletions as well as updates to references which are peeled, that is contain an object id
26    DeletionsAndNonSymbolicUpdates(Box<FindObjectFn<'a>>),
27    /// Propagate deletions as well as updates to references which are peeled, that is contain an object id. Furthermore delete the
28    /// reference which is originally updated if it exists. If it doesn't, the new value will be written into the packed ref right away.
29    /// Note that this doesn't affect symbolic references at all, which can't be placed into packed refs.
30    DeletionsAndNonSymbolicUpdatesRemoveLooseSourceReference(Box<FindObjectFn<'a>>),
31}
32
33impl Default for PackedRefs<'_> {
34    fn default() -> Self {
35        PackedRefs::DeletionsOnly
36    }
37}
38
39#[derive(Debug)]
40pub(in crate::store_impl::file) struct Edit {
41    update: RefEdit,
42    lock: Option<git_lock::Marker>,
43    /// Set if this update is coming from a symbolic reference and used to make it appear like it is the one that is handled,
44    /// instead of the referent reference.
45    parent_index: Option<usize>,
46    /// For symbolic refs, this is the previous OID to put into the reflog instead of our own previous value. It's the
47    /// peeled value of the leaf referent.
48    leaf_referent_previous_oid: Option<ObjectId>,
49}
50
51impl Edit {
52    fn name(&self) -> BString {
53        self.update.name.0.clone()
54    }
55}
56
57impl std::borrow::Borrow<RefEdit> for Edit {
58    fn borrow(&self) -> &RefEdit {
59        &self.update
60    }
61}
62
63impl std::borrow::BorrowMut<RefEdit> for Edit {
64    fn borrow_mut(&mut self) -> &mut RefEdit {
65        &mut self.update
66    }
67}
68
69/// Edits
70impl file::Store {
71    /// Open a transaction with the given `edits`, and determine how to fail if a `lock` cannot be obtained.
72    /// A snapshot of packed references will be obtained automatically if needed to fulfill this transaction
73    /// and will be provided as result of a successful transaction. Note that upon transaction failure, packed-refs
74    /// will never have been altered.
75    ///
76    /// The transaction inherits the parent namespace.
77    pub fn transaction(&self) -> Transaction<'_, '_> {
78        Transaction {
79            store: self,
80            packed_transaction: None,
81            updates: None,
82            packed_refs: PackedRefs::default(),
83        }
84    }
85}
86
87impl<'s, 'p> Transaction<'s, 'p> {
88    /// Configure the way packed refs are handled during the transaction
89    pub fn packed_refs(mut self, packed_refs: PackedRefs<'p>) -> Self {
90        self.packed_refs = packed_refs;
91        self
92    }
93}
94
95impl std::fmt::Debug for Transaction<'_, '_> {
96    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97        f.debug_struct("Transaction")
98            .field("store", self.store)
99            .field("edits", &self.updates.as_ref().map(|u| u.len()))
100            .finish_non_exhaustive()
101    }
102}
103
104///
105pub mod prepare;
106
107///
108pub mod commit;