gix_ref/store/file/mod.rs
1use std::path::PathBuf;
2
3use crate::{store::WriteReflog, Namespace};
4
5/// A store for reference which uses plain files.
6///
7/// Each ref is represented as a single file on disk in a folder structure that follows the relative path
8/// used to identify [references][crate::Reference].
9#[derive(Debug, Clone)]
10pub struct Store {
11 /// The location at which loose references can be found as per conventions of a typical git repository.
12 ///
13 /// Typical base paths are `.git` repository folders.
14 git_dir: PathBuf,
15 /// Possibly the common directory at which to find shared references. Only set if this `Store` is for a work tree.
16 common_dir: Option<PathBuf>,
17 /// The kind of hash to assume in a couple of situations. Note that currently we are able to read any valid hash from files
18 /// which might want to change one day.
19 object_hash: gix_hash::Kind,
20 /// The amount of bytes needed for `mmap` to be used to open packed refs.
21 packed_buffer_mmap_threshold: u64,
22
23 /// The way to handle reflog edits
24 pub write_reflog: WriteReflog,
25 /// The namespace to use for edits and reads
26 pub namespace: Option<Namespace>,
27 /// This is only needed on Windows, where some device names are reserved at any level of a path, so that
28 /// reading or writing `refs/heads/CON` for example would read from the console, or write to it.
29 pub prohibit_windows_device_names: bool,
30 /// If set, we will convert decomposed unicode like `a\u308` into precomposed unicode like `รค` when reading
31 /// ref names from disk.
32 /// Note that this is an internal operation that isn't observable on the outside, but it's needed for lookups
33 /// to packed-refs or symlinks to work correctly.
34 /// Iterated references will be returned verbatim, thus when sending them over the wire they have to be precomposed
35 /// as needed.
36 pub precompose_unicode: bool,
37 /// A packed buffer which can be mapped in one version and shared as such.
38 /// It's updated only in one spot, which is prior to reading it based on file stamps.
39 /// Doing it like this has the benefit of being able to hand snapshots out to people without blocking others from updating it.
40 packed: packed::modifiable::MutableSharedBuffer,
41}
42
43mod access {
44 use std::path::Path;
45
46 /// Mutation
47 impl file::Store {
48 /// Set the amount of `bytes` needed for the `.git/packed-refs` file to be memory mapped.
49 /// Returns the previous value, which is always 32KB.
50 pub fn set_packed_buffer_mmap_threshold(&mut self, mut bytes: u64) -> u64 {
51 std::mem::swap(&mut self.packed_buffer_mmap_threshold, &mut bytes);
52 bytes
53 }
54 }
55
56 use crate::{file, Target};
57
58 /// Access
59 impl file::Store {
60 /// Return the `.git` directory at which all references are loaded.
61 ///
62 /// For worktrees, this is the linked work-tree private ref location,
63 /// then [`common_dir()`][file::Store::common_dir()] is `Some(parent_git_dir)`.
64 pub fn git_dir(&self) -> &Path {
65 &self.git_dir
66 }
67
68 /// If this is a linked work tree, there will be `Some(git_dir)` pointing to the parent repository,
69 /// while [`git_dir()`][file::Store::git_dir()] points to the location holding linked work-tree private references.
70 pub fn common_dir(&self) -> Option<&Path> {
71 self.common_dir.as_deref()
72 }
73
74 /// Similar to [`common_dir()`][file::Store::common_dir()], but it will produce either the common-dir, or the git-dir if the former
75 /// isn't present.
76 ///
77 /// This is also the directory in which the packed references file would be placed.
78 pub fn common_dir_resolved(&self) -> &Path {
79 self.common_dir.as_deref().unwrap_or(&self.git_dir)
80 }
81
82 /// Return `Some(true)` if this is a freshly initialized ref store without any observable changes.
83 /// Return `None` if `HEAD` couldn't be read.
84 ///
85 /// This is the case if:
86 ///
87 /// * the ref-store is valid
88 /// * `HEAD` exists
89 /// * `HEAD` still points to `default_ref`
90 /// * there are no packed refs
91 /// * There are no observable references in `refs/`
92 pub fn is_pristine(&self, default_ref: &crate::FullNameRef) -> Option<bool> {
93 let head = self.find_loose("HEAD").ok()?;
94 match head.target {
95 Target::Object(_) => return Some(false),
96 Target::Symbolic(name) => {
97 if name.as_ref() != default_ref {
98 return Some(false);
99 }
100 }
101 }
102 if self.loose_iter().ok()?.filter_map(Result::ok).next().is_some() {
103 return Some(false);
104 }
105 if self.packed_refs_path().is_file() {
106 return Some(false);
107 }
108 Some(true)
109 }
110 }
111}
112
113/// A transaction on a file store
114pub struct Transaction<'s, 'p> {
115 store: &'s Store,
116 packed_transaction: Option<crate::store_impl::packed::Transaction>,
117 updates: Option<Vec<transaction::Edit>>,
118 packed_refs: transaction::PackedRefs<'p>,
119}
120
121///
122pub mod loose;
123mod overlay_iter;
124
125///
126pub mod iter {
127 pub use super::overlay_iter::{LooseThenPacked, Platform};
128
129 ///
130 pub mod loose_then_packed {
131 pub use super::super::overlay_iter::Error;
132 }
133}
134
135///
136pub mod log;
137
138///
139pub mod find;
140
141///
142pub mod transaction;
143
144///
145pub mod packed;
146
147mod raw_ext;
148pub use raw_ext::ReferenceExt;