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;