diff options
Diffstat (limited to 'vendor/gix/src/repository/index.rs')
-rw-r--r-- | vendor/gix/src/repository/index.rs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/vendor/gix/src/repository/index.rs b/vendor/gix/src/repository/index.rs new file mode 100644 index 000000000..a21b138a5 --- /dev/null +++ b/vendor/gix/src/repository/index.rs @@ -0,0 +1,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, + } + } +} |