1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
use gix_odb::FindExt;
use crate::{config::cache::util::ApplyLeniencyDefault, repository::IndexPersistedOrInMemory, worktree};
/// Index access
impl crate::Repository {
/// Open a new copy of the index file and decode it entirely.
///
/// It will use the `index.threads` configuration key to learn how many threads to use.
/// Note that it may fail if there is no index.
pub fn open_index(&self) -> Result<gix_index::File, worktree::open_index::Error> {
let thread_limit = self
.config
.resolved
.string("index", None, "threads")
.map(|value| crate::config::tree::Index::THREADS.try_into_index_threads(value))
.transpose()
.with_lenient_default(self.config.lenient_config)?;
let skip_hash = self
.config
.resolved
.boolean("index", None, "skipHash")
.map(|res| crate::config::tree::Index::SKIP_HASH.enrich_error(res))
.transpose()
.with_lenient_default(self.config.lenient_config)?
.unwrap_or_default();
let index = gix_index::File::at(
self.index_path(),
self.object_hash(),
skip_hash,
gix_index::decode::Options {
thread_limit,
min_extension_block_in_bytes_for_threading: 0,
expected_checksum: None,
},
)?;
Ok(index)
}
/// Return a shared worktree index which is updated automatically if the in-memory snapshot has become stale as the underlying file
/// on disk has changed.
///
/// The index file is shared across all clones of this repository.
pub fn index(&self) -> Result<worktree::Index, worktree::open_index::Error> {
self.try_index().and_then(|opt| match opt {
Some(index) => Ok(index),
None => Err(worktree::open_index::Error::IndexFile(
gix_index::file::init::Error::Io(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Could not find index file at {:?} for opening.", self.index_path()),
)),
)),
})
}
/// Return a shared worktree index which is updated automatically if the in-memory snapshot has become stale as the underlying file
/// on disk has changed, or `None` if no such file exists.
///
/// The index file is shared across all clones of this repository.
pub fn try_index(&self) -> Result<Option<worktree::Index>, worktree::open_index::Error> {
self.index.recent_snapshot(
|| self.index_path().metadata().and_then(|m| m.modified()).ok(),
|| {
self.open_index().map(Some).or_else(|err| match err {
worktree::open_index::Error::IndexFile(gix_index::file::init::Error::Io(err))
if err.kind() == std::io::ErrorKind::NotFound =>
{
Ok(None)
}
err => Err(err),
})
},
)
}
/// Open the persisted worktree index or generate it from the current `HEAD^{tree}` to live in-memory only.
///
/// Use this method to get an index in any repository, even bare ones that don't have one naturally.
///
/// ### Note
///
/// The locally stored index is not guaranteed to represent `HEAD^{tree}` if this repository is bare - bare repos
/// don't naturally have an index and if an index is present it must have been generated by hand.
pub fn index_or_load_from_head(
&self,
) -> Result<IndexPersistedOrInMemory, crate::repository::index_or_load_from_head::Error> {
Ok(match self.try_index()? {
Some(index) => IndexPersistedOrInMemory::Persisted(index),
None => {
let tree = self.head_commit()?.tree_id()?;
IndexPersistedOrInMemory::InMemory(self.index_from_tree(&tree)?)
}
})
}
/// Create new index-file, which would live at the correct location, in memory from the given `tree`.
///
/// Note that this is an expensive operation as it requires recursively traversing the entire tree to unpack it into the index.
pub fn index_from_tree(
&self,
tree: &gix_hash::oid,
) -> Result<gix_index::File, gix_traverse::tree::breadthfirst::Error> {
Ok(gix_index::File::from_state(
gix_index::State::from_tree(tree, |oid, buf| self.objects.find_tree_iter(oid, buf).ok())?,
self.git_dir().join("index"),
))
}
}
impl std::ops::Deref for IndexPersistedOrInMemory {
type Target = gix_index::File;
fn deref(&self) -> &Self::Target {
match self {
IndexPersistedOrInMemory::Persisted(i) => i,
IndexPersistedOrInMemory::InMemory(i) => i,
}
}
}
impl IndexPersistedOrInMemory {
/// Consume this instance and turn it into an owned index file.
///
/// Note that this will cause the persisted index to be cloned, which would happen whenever the repository has a worktree.
pub fn into_owned(self) -> gix_index::File {
match self {
IndexPersistedOrInMemory::Persisted(i) => gix_index::File::clone(&i),
IndexPersistedOrInMemory::InMemory(i) => i,
}
}
}