Skip to content

Commit

Permalink
feat: add Repository::index_or_load_from_head_or_empty().
Browse files Browse the repository at this point in the history
It's useful to get a reasonable index in any case, even on unborn repositories.
It's for cases where the `HEAD` isn't setup at all, despite content being available,
and to avoid unnecessary restrictions on what works.
  • Loading branch information
Byron committed Nov 5, 2024
1 parent 2fce14f commit 1f9556a
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 10 deletions.
2 changes: 1 addition & 1 deletion gix/src/repository/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Repository {
mode: gix_diff::blob::pipeline::Mode,
worktree_roots: gix_diff::blob::pipeline::WorktreeRoots,
) -> Result<gix_diff::blob::Platform, diff_resource_cache::Error> {
let index = self.index_or_load_from_head()?;
let index = self.index_or_load_from_head_or_empty()?;
Ok(crate::diff::resource_cache(
self,
mode,
Expand Down
29 changes: 27 additions & 2 deletions gix/src/repository/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ impl crate::Repository {
///
/// ### 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.
/// * 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.
/// * This method will fail on unborn repositories as `HEAD` doesn't point to a reference yet, which is needed to resolve
/// the revspec. If that is a concern, use [`Self::index_or_load_from_head_or_empty()`] instead.
pub fn index_or_load_from_head(
&self,
) -> Result<IndexPersistedOrInMemory, crate::repository::index_or_load_from_head::Error> {
Expand All @@ -110,6 +112,29 @@ impl crate::Repository {
})
}

/// Open the persisted worktree index or generate it from the current `HEAD^{tree}` to live in-memory only,
/// or resort to an empty index if `HEAD` is unborn.
///
/// Use this method to get an index in any repository, even bare ones that don't have one naturally, or those
/// that are in a state where `HEAD` is invalid or points to an unborn reference.
pub fn index_or_load_from_head_or_empty(
&self,
) -> Result<IndexPersistedOrInMemory, crate::repository::index_or_load_from_head_or_empty::Error> {
Ok(match self.try_index()? {
Some(index) => IndexPersistedOrInMemory::Persisted(index),
None => match self.head()?.id() {
Some(id) => {
let head_tree_id = id.object()?.peel_to_commit()?.tree_id()?;
IndexPersistedOrInMemory::InMemory(self.index_from_tree(&head_tree_id)?)
}
None => IndexPersistedOrInMemory::InMemory(gix_index::File::from_state(
gix_index::State::new(self.object_hash()),
self.index_path(),
)),
},
})
}

/// 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.
Expand Down
2 changes: 1 addition & 1 deletion gix/src/repository/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Repository {
&self,
worktree_roots: gix_merge::blob::pipeline::WorktreeRoots,
) -> Result<gix_merge::blob::Platform, merge_resource_cache::Error> {
let index = self.index_or_load_from_head()?;
let index = self.index_or_load_from_head_or_empty()?;
let mode = {
let renormalize = self
.config
Expand Down
32 changes: 27 additions & 5 deletions gix/src/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub mod merge_resource_cache {
#[error(transparent)]
PipelineOptions(#[from] crate::config::merge::pipeline_options::Error),
#[error(transparent)]
Index(#[from] crate::repository::index_or_load_from_head::Error),
Index(#[from] crate::repository::index_or_load_from_head_or_empty::Error),
#[error(transparent)]
AttributeStack(#[from] crate::config::attribute_stack::Error),
#[error(transparent)]
Expand Down Expand Up @@ -154,7 +154,7 @@ pub mod diff_resource_cache {
#[error("Could not obtain resource cache for diffing")]
ResourceCache(#[from] crate::diff::resource_cache::Error),
#[error(transparent)]
Index(#[from] crate::repository::index_or_load_from_head::Error),
Index(#[from] crate::repository::index_or_load_from_head_or_empty::Error),
#[error(transparent)]
AttributeStack(#[from] crate::config::attribute_stack::Error),
}
Expand Down Expand Up @@ -289,7 +289,7 @@ pub mod pathspec_defaults_ignore_case {
///
#[cfg(feature = "index")]
pub mod index_or_load_from_head {
/// The error returned by [`Repository::index_or_load_from_head()`][crate::Repository::index_or_load_from_head()].
/// The error returned by [`Repository::index_or_load_from_head()`](crate::Repository::index_or_load_from_head()).
#[derive(thiserror::Error, Debug)]
#[allow(missing_docs)]
pub enum Error {
Expand All @@ -304,10 +304,32 @@ pub mod index_or_load_from_head {
}
}

///
#[cfg(feature = "index")]
pub mod index_or_load_from_head_or_empty {
/// The error returned by [`Repository::index_or_load_from_head_or_empty()`](crate::Repository::index_or_load_from_head_or_empty()).
#[derive(thiserror::Error, Debug)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
ReadHead(#[from] crate::reference::find::existing::Error),
#[error(transparent)]
FindCommit(#[from] crate::object::find::existing::Error),
#[error(transparent)]
PeelToTree(#[from] crate::object::peel::to_kind::Error),
#[error(transparent)]
TreeId(#[from] gix_object::decode::Error),
#[error(transparent)]
TraverseTree(#[from] crate::repository::index_from_tree::Error),
#[error(transparent)]
OpenIndex(#[from] crate::worktree::open_index::Error),
}
}

///
#[cfg(feature = "worktree-stream")]
pub mod worktree_stream {
/// The error returned by [`Repository::worktree_stream()`][crate::Repository::worktree_stream()].
/// The error returned by [`Repository::worktree_stream()`](crate::Repository::worktree_stream()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
Expand All @@ -332,6 +354,6 @@ pub mod worktree_stream {
///
#[cfg(feature = "worktree-archive")]
pub mod worktree_archive {
/// The error returned by [`Repository::worktree_archive()`][crate::Repository::worktree_archive()].
/// The error returned by [`Repository::worktree_archive()`](crate::Repository::worktree_archive()).
pub type Error = gix_archive::Error;
}
Binary file modified gix/tests/fixtures/generated-archives/make_basic_repo.tar
Binary file not shown.
4 changes: 3 additions & 1 deletion gix/tests/fixtures/make_basic_repo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ git init empty-core-excludes
git clone --bare . non-bare-without-worktree
(cd non-bare-without-worktree
git config core.bare false
)
)

git init unborn;
18 changes: 18 additions & 0 deletions gix/tests/gix/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ mod state;
mod submodule;
mod worktree;

#[cfg(feature = "index")]
mod index {
#[test]
fn basics() -> crate::Result {
let repo = crate::named_subrepo_opts("make_basic_repo.sh", "unborn", gix::open::Options::isolated())?;
assert!(
repo.index_or_load_from_head().is_err(),
"can't read index if `HEAD^{{tree}}` can't be resolved"
);
assert!(
repo.index_or_load_from_head_or_empty()?.entries().is_empty(),
"an empty index is created on the fly"
);
Ok(())
}
}

#[cfg(feature = "dirwalk")]
mod dirwalk {
use gix_dir::entry::Kind::*;
Expand Down Expand Up @@ -44,6 +61,7 @@ mod dirwalk {
("non-bare-repo-without-index".into(), Repository),
("non-bare-without-worktree".into(), Directory),
("some".into(), Directory),
("unborn".into(), Repository),
];
assert_eq!(
collect
Expand Down

0 comments on commit 1f9556a

Please sign in to comment.