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;