From a049bd3de924113a011057aa4e76a8df3b28d437 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 2 Aug 2022 10:07:06 +0800 Subject: [PATCH] Index lookup works and provides hints en-par with git in terms of information at least. (#427) --- .../src/revision/spec/parse/delegate.rs | 34 ++++++++++++++++--- .../src/revision/spec/parse/types.rs | 7 ++++ .../make_rev_spec_parse_repos.tar.xz | 2 +- .../fixtures/make_rev_spec_parse_repos.sh | 2 ++ .../tests/revision/spec/from_bytes/mod.rs | 7 ++-- 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/git-repository/src/revision/spec/parse/delegate.rs b/git-repository/src/revision/spec/parse/delegate.rs index 385daaf038..a4d7a876ad 100644 --- a/git-repository/src/revision/spec/parse/delegate.rs +++ b/git-repository/src/revision/spec/parse/delegate.rs @@ -523,12 +523,38 @@ impl<'repo> delegate::Navigate for Delegate<'repo> { } } - fn index_lookup(&mut self, _path: &BStr, _stage: u8) -> Option<()> { + fn index_lookup(&mut self, path: &BStr, stage: u8) -> Option<()> { self.unset_disambiguate_call(); match self.repo.index() { - Ok(_index) => { - todo!("index lookup") - } + Ok(index) => match index.entry_by_path_and_stage(path, stage.into()) { + Some(entry) => { + self.objs[self.idx] + .get_or_insert_with(HashSet::default) + .insert(entry.id); + Some(()) + } + None => { + let stage_hint = [0, 1, 2] + .iter() + .filter(|our_stage| **our_stage != stage) + .find_map(|stage| { + index + .entry_index_by_path_and_stage(path, (*stage).into()) + .map(|_| (*stage).into()) + }); + let exists = self + .repo + .work_dir() + .map_or(false, |root| root.join(git_path::from_bstr(path)).exists()); + self.err.push(Error::IndexLookup { + desired_path: path.into(), + desired_stage: stage.into(), + exists, + stage_hint, + }); + None + } + }, Err(err) => { self.err.push(err.into()); None diff --git a/git-repository/src/revision/spec/parse/types.rs b/git-repository/src/revision/spec/parse/types.rs index 0c0fdcabae..28c181bfb5 100644 --- a/git-repository/src/revision/spec/parse/types.rs +++ b/git-repository/src/revision/spec/parse/types.rs @@ -61,6 +61,13 @@ pub struct Options { #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { + #[error("Path {desired_path:?} did not exist in index at stage {desired_stage}{}{}", stage_hint.map(|actual|format!(". It does exist at stage {actual}")).unwrap_or_default(), exists.then(|| ". It exists on disk").unwrap_or(". It does not exist on disk"))] + IndexLookup { + desired_path: BString, + desired_stage: git_index::entry::Stage, + stage_hint: Option, + exists: bool, + }, #[error(transparent)] Index(#[from] crate::worktree::open_index::Error), #[error(transparent)] diff --git a/git-repository/tests/fixtures/generated-archives/make_rev_spec_parse_repos.tar.xz b/git-repository/tests/fixtures/generated-archives/make_rev_spec_parse_repos.tar.xz index 3cb213da49..4cade160c6 100644 --- a/git-repository/tests/fixtures/generated-archives/make_rev_spec_parse_repos.tar.xz +++ b/git-repository/tests/fixtures/generated-archives/make_rev_spec_parse_repos.tar.xz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:806e9ac9f3405d6c2547029d21e1de0a508291aa968296063cf9bd22aeae3f3e +oid sha256:e40c952da2d14b24fd94d1a47c7c753d634674145c938853af39a922453a7c57 size 27956 diff --git a/git-repository/tests/fixtures/make_rev_spec_parse_repos.sh b/git-repository/tests/fixtures/make_rev_spec_parse_repos.sh index 5ee8eaa80c..b108bdd662 100644 --- a/git-repository/tests/fixtures/make_rev_spec_parse_repos.sh +++ b/git-repository/tests/fixtures/make_rev_spec_parse_repos.sh @@ -344,4 +344,6 @@ git init complex_graph baseline ":/not there" # definitely not in graph baseline "@^{/!-B}" # negation from branch baseline ":file" # index lookup, default stage 0 + baseline ":1:file" # stage 1 + baseline ":foo" # not found ) diff --git a/git-repository/tests/revision/spec/from_bytes/mod.rs b/git-repository/tests/revision/spec/from_bytes/mod.rs index ddf7a4b953..96b13f5b59 100644 --- a/git-repository/tests/revision/spec/from_bytes/mod.rs +++ b/git-repository/tests/revision/spec/from_bytes/mod.rs @@ -14,8 +14,7 @@ mod index { use git_testtools::hex_to_id; #[test] - #[ignore] - fn at_default_stage() { + fn at_stages() { let repo = repo("complex_graph").unwrap(); assert_eq!( parse_spec(":file", &repo).unwrap(), @@ -24,12 +23,12 @@ mod index { assert_eq!( parse_spec(":1:file", &repo).unwrap_err().to_string(), - "give hint as to where to find the file in the index and if it exists on disk", + "Path \"file\" did not exist in index at stage 1. It does exist at stage 0. It exists on disk", ); assert_eq!( parse_spec(":foo", &repo).unwrap_err().to_string(), - "does not exist (but use same error message as above, as it's parametric)", + "Path \"foo\" did not exist in index at stage 0. It does not exist on disk", ); } }