diff --git a/gix-worktree-stream/src/entry.rs b/gix-worktree-stream/src/entry.rs index 4d7314db259..b8ef2c5afcc 100644 --- a/gix-worktree-stream/src/entry.rs +++ b/gix-worktree-stream/src/entry.rs @@ -13,8 +13,10 @@ use crate::{protocol, Entry, Stream}; pub enum Error { #[error(transparent)] Io(#[from] std::io::Error), - #[error("Could not find a blob or tree for archival")] - Find(#[source] Box), + #[error("Could not find a tree's leaf, typically a blob")] + Find(#[from] gix_object::find::existing::Error), + #[error("Could not find a tree to traverse")] + FindTree(#[from] gix_object::find::existing_iter::Error), #[error("Could not query attributes for path \"{path}\"")] Attributes { path: BString, diff --git a/gix-worktree-stream/src/from_tree/mod.rs b/gix-worktree-stream/src/from_tree/mod.rs index e59892b6b33..0afd354ef67 100644 --- a/gix-worktree-stream/src/from_tree/mod.rs +++ b/gix-worktree-stream/src/from_tree/mod.rs @@ -1,10 +1,11 @@ use std::io::Write; use gix_object::bstr::BStr; +use gix_object::FindExt; use crate::{entry, entry::Error, protocol, AdditionalEntry, SharedErrorSlot, Stream}; -/// Use `find` to traverse `tree` and fetch the contained blobs to return as [`Stream`], which makes them queryable +/// Use `objects` to traverse `tree` and fetch the contained blobs to return as [`Stream`], which makes them queryable /// on demand with support for streaming each entry. /// /// `pipeline` is used to convert blobs to their worktree representation, and `attributes` is used to read @@ -32,18 +33,17 @@ use crate::{entry, entry::Error, protocol, AdditionalEntry, SharedErrorSlot, Str /// ### Limitations /// /// * `export-subst` is not support, as it requires the entire formatting engine of `git log`. -pub fn from_tree( +pub fn from_tree( tree: gix_hash::ObjectId, - find: Find, + objects: Find, pipeline: gix_filter::Pipeline, - attributes: impl FnMut(&BStr, gix_object::tree::EntryMode, &mut gix_attributes::search::Outcome) -> Result<(), E2> + attributes: impl FnMut(&BStr, gix_object::tree::EntryMode, &mut gix_attributes::search::Outcome) -> Result<(), E> + Send + 'static, ) -> Stream where - Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec) -> Result, E1> + Clone + Send + 'static, - E1: std::error::Error + Send + Sync + 'static, - E2: std::error::Error + Send + Sync + 'static, + Find: gix_object::Find + Clone + Send + 'static, + E: std::error::Error + Send + Sync + 'static, { let (stream, mut write, additional_entries) = Stream::new(); std::thread::spawn({ @@ -51,7 +51,7 @@ where move || { if let Err(err) = run( tree, - find, + objects, pipeline, attributes, &mut write, @@ -76,11 +76,11 @@ where stream } -fn run( +fn run( tree: gix_hash::ObjectId, - mut find: Find, + objects: Find, mut pipeline: gix_filter::Pipeline, - mut attributes: impl FnMut(&BStr, gix_object::tree::EntryMode, &mut gix_attributes::search::Outcome) -> Result<(), E2> + mut attributes: impl FnMut(&BStr, gix_object::tree::EntryMode, &mut gix_attributes::search::Outcome) -> Result<(), E> + Send + 'static, out: &mut gix_features::io::pipe::Writer, @@ -88,16 +88,14 @@ fn run( additional_entries: std::sync::mpsc::Receiver, ) -> Result<(), Error> where - Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec) -> Result, E1> + Clone + Send + 'static, - E1: std::error::Error + Send + Sync + 'static, - E2: std::error::Error + Send + Sync + 'static, + Find: gix_object::Find + Clone, + E: std::error::Error + Send + Sync + 'static, { let mut buf = Vec::new(); - let obj = find(tree.as_ref(), &mut buf).map_err(|err| Error::Find(Box::new(err)))?; + let tree_iter = objects.find_tree_iter(tree.as_ref(), &mut buf)?; if pipeline.driver_context_mut().treeish.is_none() { pipeline.driver_context_mut().treeish = Some(tree); } - let tree = gix_object::TreeRefIter::from_bytes(obj.data); let mut attrs = gix_attributes::search::Outcome::default(); attrs.initialize_with_selection(&Default::default(), Some("export-ignore")); @@ -106,10 +104,7 @@ where err, pipeline, attrs, - find: { - let mut find = find.clone(); - move |a: &gix_hash::oid, b: &mut Vec| find(a, b).map_err(|err| Error::Find(Box::new(err))) - }, + objects: objects.clone(), fetch_attributes: move |a: &BStr, b: gix_object::tree::EntryMode, c: &mut gix_attributes::search::Outcome| { attributes(a, b, c).map_err(|err| Error::Attributes { source: Box::new(err), @@ -121,13 +116,9 @@ where buf: Vec::with_capacity(1024), }; gix_traverse::tree::breadthfirst( - tree, + tree_iter, gix_traverse::tree::breadthfirst::State::default(), - |id, buf| { - find(id, buf) - .map(|obj| gix_object::TreeRefIter::from_bytes(obj.data)) - .ok() - }, + &objects, &mut dlg, )?; diff --git a/gix-worktree-stream/src/from_tree/traverse.rs b/gix-worktree-stream/src/from_tree/traverse.rs index df242b304e9..378054c5d22 100644 --- a/gix-worktree-stream/src/from_tree/traverse.rs +++ b/gix-worktree-stream/src/from_tree/traverse.rs @@ -3,15 +3,15 @@ use std::{collections::VecDeque, io::Write}; use gix_filter::{driver::apply::MaybeDelayed, pipeline::convert::ToWorktreeOutcome}; use gix_object::{ bstr::{BStr, BString, ByteSlice, ByteVec}, - tree, + tree, FindExt, }; use gix_traverse::tree::{visit::Action, Visit}; use crate::{entry::Error, protocol, SharedErrorSlot}; -pub struct Delegate<'a, AttributesFn, FindFn> +pub struct Delegate<'a, AttributesFn, Find> where - FindFn: for<'b> FnMut(&gix_hash::oid, &'b mut Vec) -> Result, Error> + 'static, + Find: gix_object::Find, { pub(crate) out: &'a mut gix_features::io::pipe::Writer, pub(crate) err: SharedErrorSlot, @@ -20,13 +20,13 @@ where pub(crate) pipeline: gix_filter::Pipeline, pub(crate) attrs: gix_attributes::search::Outcome, pub(crate) fetch_attributes: AttributesFn, - pub(crate) find: FindFn, + pub(crate) objects: Find, pub(crate) buf: Vec, } -impl Delegate<'_, AttributesFn, FindFn> +impl Delegate<'_, AttributesFn, Find> where - FindFn: for<'b> FnMut(&gix_hash::oid, &'b mut Vec) -> Result, Error> + 'static, + Find: gix_object::Find, AttributesFn: FnMut(&BStr, gix_object::tree::EntryMode, &mut gix_attributes::search::Outcome) -> Result<(), Error> + 'static, { @@ -62,7 +62,7 @@ where if self.ignore_state().is_set() { return Ok(Action::Continue); } - (self.find)(entry.oid, &mut self.buf)?; + self.objects.find(entry.oid, &mut self.buf)?; self.pipeline.driver_context_mut().blob = Some(entry.oid.into()); let converted = self.pipeline.convert_to_worktree( @@ -99,9 +99,9 @@ where } } -impl Visit for Delegate<'_, AttributesFn, FindFn> +impl Visit for Delegate<'_, AttributesFn, Find> where - FindFn: for<'a> FnMut(&gix_hash::oid, &'a mut Vec) -> Result, Error> + 'static, + Find: gix_object::Find, AttributesFn: FnMut(&BStr, gix_object::tree::EntryMode, &mut gix_attributes::search::Outcome) -> Result<(), Error> + 'static, { diff --git a/gix-worktree-stream/tests/stream.rs b/gix-worktree-stream/tests/stream.rs index 44e97d1a918..a09e3852636 100644 --- a/gix-worktree-stream/tests/stream.rs +++ b/gix-worktree-stream/tests/stream.rs @@ -12,34 +12,45 @@ mod from_tree { }; use gix_attributes::glob::pattern::Case; - use gix_object::FindExt; + use gix_hash::oid; use gix_object::{bstr::ByteSlice, tree::EntryMode}; + use gix_object::{Data, FindExt}; use gix_testtools::once_cell::sync::Lazy; use gix_worktree::stack::state::attributes::Source; use crate::hex_to_id; + #[derive(Clone)] + struct FailObjectRetrieval; + + impl gix_object::Find for FailObjectRetrieval { + fn try_find<'a>( + &self, + _id: &oid, + _buffer: &'a mut Vec, + ) -> Result>, gix_object::find::Error> { + Err(Box::new(Error::new(ErrorKind::Other, "object retrieval failed"))) + } + } + #[test] fn can_receive_err_if_root_is_not_found() { let mut stream = gix_worktree_stream::from_tree( gix_hash::Kind::Sha1.null(), - |_, _| Err(Error::new(ErrorKind::Other, "object retrieval failed")), + FailObjectRetrieval, mutating_pipeline(false), |_, _, _| -> Result<_, Infallible> { unreachable!("must not be called") }, ); let err = stream.next_entry().unwrap_err(); - assert_eq!(err.to_string(), "Could not find a blob or tree for archival"); + assert_eq!(err.to_string(), "Could not find a tree to traverse"); } #[test] fn can_receive_err_if_attribute_not_found() -> gix_testtools::Result { let (_dir, head_tree, odb, _cache) = basic()?; - let mut stream = gix_worktree_stream::from_tree( - head_tree, - move |id, buf| odb.find(id, buf), - mutating_pipeline(false), - |_, _, _| Err(Error::new(ErrorKind::Other, "attribute retrieval failed")), - ); + let mut stream = gix_worktree_stream::from_tree(head_tree, odb, mutating_pipeline(false), |_, _, _| { + Err(Error::new(ErrorKind::Other, "attribute retrieval failed")) + }); let err = stream.next_entry().unwrap_err(); assert_eq!( err.to_string(), @@ -53,10 +64,7 @@ mod from_tree { let (dir, head_tree, odb, mut cache) = basic()?; let mut stream = gix_worktree_stream::from_tree( head_tree, - { - let odb = odb.clone(); - move |id, buf| odb.find(id, buf) - }, + odb.clone(), mutating_pipeline(true), move |rela_path, mode, attrs| { cache @@ -214,10 +222,7 @@ mod from_tree { let (_dir, head_tree, odb, mut cache) = basic()?; let mut stream = gix_worktree_stream::from_tree( head_tree, - { - let odb = odb.clone(); - move |id, buf| odb.find(id, buf) - }, + odb.clone(), mutating_pipeline(false), move |rela_path, mode, attrs| { cache diff --git a/gix-worktree/src/stack/delegate.rs b/gix-worktree/src/stack/delegate.rs index 8e48057dea7..1234346c5de 100644 --- a/gix-worktree/src/stack/delegate.rs +++ b/gix-worktree/src/stack/delegate.rs @@ -18,19 +18,13 @@ pub struct Statistics { pub pop_directory: usize, } -pub(crate) type FindFn<'a> = dyn for<'b> FnMut( - &gix_hash::oid, - &'b mut Vec, - ) -> Result, Box> - + 'a; - pub(crate) struct StackDelegate<'a, 'find> { pub state: &'a mut State, pub buf: &'a mut Vec, #[cfg_attr(not(feature = "attributes"), allow(dead_code))] pub is_dir: bool, pub id_mappings: &'a Vec, - pub find: &'find mut FindFn<'find>, + pub objects: &'find dyn gix_object::Find, pub case: gix_glob::pattern::Case, pub statistics: &'a mut super::Statistics, } @@ -63,7 +57,7 @@ impl<'a, 'find> gix_fs::stack::Delegate for StackDelegate<'a, 'find> { rela_dir, self.buf, self.id_mappings, - self.find, + self.objects, &mut self.statistics.attributes, )?; } @@ -75,7 +69,7 @@ impl<'a, 'find> gix_fs::stack::Delegate for StackDelegate<'a, 'find> { rela_dir, self.buf, self.id_mappings, - &mut self.find, + self.objects, &mut self.statistics.attributes, )?; ignore.push_directory( @@ -84,7 +78,7 @@ impl<'a, 'find> gix_fs::stack::Delegate for StackDelegate<'a, 'find> { rela_dir, self.buf, self.id_mappings, - &mut self.find, + self.objects, self.case, &mut self.statistics.ignore, )? @@ -95,7 +89,7 @@ impl<'a, 'find> gix_fs::stack::Delegate for StackDelegate<'a, 'find> { rela_dir, self.buf, self.id_mappings, - &mut self.find, + self.objects, self.case, &mut self.statistics.ignore, )?, diff --git a/gix-worktree/src/stack/mod.rs b/gix-worktree/src/stack/mod.rs index 228467f5bee..387acf2acff 100644 --- a/gix-worktree/src/stack/mod.rs +++ b/gix-worktree/src/stack/mod.rs @@ -2,7 +2,6 @@ use std::path::{Path, PathBuf}; use bstr::{BStr, ByteSlice}; -use gix_hash::oid; use super::Stack; use crate::PathIdMapping; @@ -106,18 +105,17 @@ impl Stack { /// symlinks are in that path. /// Unless `is_dir` is known with `Some(…)`, then `relative` points to a directory itself in which case the entire resulting /// path is created as directory. If it's not known it is assumed to be a file. - /// `find` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()], with mappnigs + /// `objects` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()], with mappnigs /// /// Provide access to cached information for that `relative` path via the returned platform. - pub fn at_path( + pub fn at_path( &mut self, relative: impl AsRef, is_dir: Option, - mut find: Find, + objects: Find, ) -> std::io::Result> where - Find: for<'a> FnMut(&oid, &'a mut Vec) -> Result, E>, - E: std::error::Error + Send + Sync + 'static, + Find: gix_object::Find, { self.statistics.platforms += 1; let mut delegate = StackDelegate { @@ -125,7 +123,7 @@ impl Stack { buf: &mut self.buf, is_dir: is_dir.unwrap_or(false), id_mappings: &self.id_mappings, - find: &mut |oid, buf| Ok(find(oid, buf).map_err(Box::new)?), + objects: &objects, case: self.case, statistics: &mut self.statistics, }; @@ -136,7 +134,7 @@ impl Stack { /// Obtain a platform for lookups from a repo-`relative` path, typically obtained from an index entry. `is_dir` should reflect /// whether it's a directory or not, or left at `None` if unknown. - /// `find` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()]. + /// `objects` maybe used to lookup objects from an [id mapping][crate::stack::State::id_mappings_from_index()]. /// All effects are similar to [`at_path()`][Self::at_path()]. /// /// If `relative` ends with `/` and `is_dir` is `None`, it is automatically assumed to be a directory. @@ -144,15 +142,14 @@ impl Stack { /// ### Panics /// /// on illformed UTF8 in `relative` - pub fn at_entry<'r, Find, E>( + pub fn at_entry<'r, Find>( &mut self, relative: impl Into<&'r BStr>, is_dir: Option, - find: Find, + objects: Find, ) -> std::io::Result> where - Find: for<'a> FnMut(&oid, &'a mut Vec) -> Result, E>, - E: std::error::Error + Send + Sync + 'static, + Find: gix_object::Find, { let relative = relative.into(); let relative_path = gix_path::from_bstr(relative); @@ -160,7 +157,7 @@ impl Stack { self.at_path( relative_path, is_dir.or_else(|| relative.ends_with_str("/").then_some(true)), - find, + objects, ) } } diff --git a/gix-worktree/src/stack/state/attributes.rs b/gix-worktree/src/stack/state/attributes.rs index d49de1288c1..04ad8b5c712 100644 --- a/gix-worktree/src/stack/state/attributes.rs +++ b/gix-worktree/src/stack/state/attributes.rs @@ -2,8 +2,8 @@ use std::path::{Path, PathBuf}; use bstr::{BStr, ByteSlice}; use gix_glob::pattern::Case; +use gix_object::FindExt; -use crate::stack::delegate::FindFn; use crate::{ stack::state::{AttributeMatchGroup, Attributes}, PathIdMapping, Stack, @@ -95,7 +95,7 @@ impl Attributes { rela_dir: &BStr, buf: &mut Vec, id_mappings: &[PathIdMapping], - find: &mut FindFn<'_>, + objects: &dyn gix_object::Find, stats: &mut Statistics, ) -> std::io::Result<()> { let attr_path_relative = @@ -109,7 +109,8 @@ impl Attributes { match self.source { Source::IdMapping | Source::IdMappingThenWorktree => { if let Ok(idx) = attr_file_in_index { - let blob = find(&id_mappings[idx].1, buf) + let blob = objects + .find_blob(&id_mappings[idx].1, buf) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; let attr_path = gix_path::from_bstring(attr_path_relative.into_owned()); self.stack.add_patterns_buffer( @@ -147,7 +148,8 @@ impl Attributes { stats.pattern_files += usize::from(added); stats.tried_pattern_files += 1; if let Some(idx) = attr_file_in_index.ok().filter(|_| !added) { - let blob = find(&id_mappings[idx].1, buf) + let blob = objects + .find_blob(&id_mappings[idx].1, buf) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; let attr_path = gix_path::from_bstring(attr_path_relative.into_owned()); self.stack.add_patterns_buffer( diff --git a/gix-worktree/src/stack/state/ignore.rs b/gix-worktree/src/stack/state/ignore.rs index e2a2d5a3d99..370459053b8 100644 --- a/gix-worktree/src/stack/state/ignore.rs +++ b/gix-worktree/src/stack/state/ignore.rs @@ -2,8 +2,8 @@ use std::path::Path; use bstr::{BStr, ByteSlice}; use gix_glob::pattern::Case; +use gix_object::FindExt; -use crate::stack::delegate::FindFn; use crate::{ stack::state::{Ignore, IgnoreMatchGroup}, PathIdMapping, @@ -164,7 +164,7 @@ impl Ignore { rela_dir: &BStr, buf: &mut Vec, id_mappings: &[PathIdMapping], - find: &mut FindFn<'_>, + objects: &dyn gix_object::Find, case: Case, stats: &mut Statistics, ) -> std::io::Result<()> { @@ -177,7 +177,8 @@ impl Ignore { Source::IdMapping => { match ignore_file_in_index { Ok(idx) => { - let ignore_blob = find(&id_mappings[idx].1, buf) + let ignore_blob = objects + .find_blob(&id_mappings[idx].1, buf) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; let ignore_path = gix_path::from_bstring(ignore_path_relative.into_owned()); self.stack @@ -204,7 +205,8 @@ impl Ignore { if !added { match ignore_file_in_index { Ok(idx) => { - let ignore_blob = find(&id_mappings[idx].1, buf) + let ignore_blob = objects + .find_blob(&id_mappings[idx].1, buf) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; let ignore_path = gix_path::from_bstring(ignore_path_relative.into_owned()); self.stack diff --git a/gix-worktree/tests/worktree/stack/attributes.rs b/gix-worktree/tests/worktree/stack/attributes.rs index a563a51468e..d595a9e2860 100644 --- a/gix-worktree/tests/worktree/stack/attributes.rs +++ b/gix-worktree/tests/worktree/stack/attributes.rs @@ -29,9 +29,7 @@ fn baseline() -> crate::Result { let mut actual = cache.attribute_matches(); let input = std::fs::read(base.join("baseline"))?; for (rela_path, expected) in (baseline::Expectations { lines: input.lines() }) { - let entry = cache.at_entry(rela_path, None, |_, _| -> Result<_, std::convert::Infallible> { - unreachable!("we provide not id-mappings") - })?; + let entry = cache.at_entry(rela_path, None, gix_object::find::Never)?; let has_match = entry.matching_attributes(&mut actual); assert_eq!( @@ -52,9 +50,7 @@ fn baseline() -> crate::Result { let mut actual = cache.selected_attribute_matches(["info", "test"]); let input = std::fs::read(base.join("baseline.selected"))?; for (rela_path, expected) in (baseline::Expectations { lines: input.lines() }) { - let entry = cache.at_entry(rela_path, None, |_, _| -> Result<_, std::convert::Infallible> { - unreachable!("we provide not id-mappings") - })?; + let entry = cache.at_entry(rela_path, None, gix_object::find::Never)?; let has_match = entry.matching_attributes(&mut actual); assert_eq!( diff --git a/gix-worktree/tests/worktree/stack/create_directory.rs b/gix-worktree/tests/worktree/stack/create_directory.rs index 7d21c550394..4ae15cf70f6 100644 --- a/gix-worktree/tests/worktree/stack/create_directory.rs +++ b/gix-worktree/tests/worktree/stack/create_directory.rs @@ -3,11 +3,6 @@ use std::path::Path; use gix_testtools::tempfile::{tempdir, TempDir}; use gix_worktree::{stack, Stack}; -#[allow(clippy::ptr_arg)] -fn panic_on_find<'buf>(_oid: &gix_hash::oid, _buf: &'buf mut Vec) -> std::io::Result> { - unreachable!("find should not be called") -} - #[test] fn root_is_assumed_to_exist_and_files_in_root_do_not_create_directory() -> crate::Result { let dir = tempdir()?; @@ -20,7 +15,7 @@ fn root_is_assumed_to_exist_and_files_in_root_do_not_create_directory() -> crate ); assert_eq!(cache.statistics().delegate.num_mkdir_calls, 0); - let path = cache.at_path("hello", Some(false), panic_on_find)?.path(); + let path = cache.at_path("hello", Some(false), gix_object::find::Never)?.path(); assert!(!path.parent().unwrap().exists(), "prefix itself is never created"); assert_eq!(cache.statistics().delegate.num_mkdir_calls, 0); Ok(()) @@ -38,7 +33,7 @@ fn directory_paths_are_created_in_full() { ("link", None), ] { let path = cache - .at_path(Path::new("dir").join(name), *is_dir, panic_on_find) + .at_path(Path::new("dir").join(name), *is_dir, gix_object::find::Never) .unwrap() .path(); assert!(path.parent().unwrap().is_dir(), "dir exists"); @@ -52,7 +47,7 @@ fn existing_directories_are_fine() -> crate::Result { let (mut cache, tmp) = new_cache(); std::fs::create_dir(tmp.path().join("dir"))?; - let path = cache.at_path("dir/file", Some(false), panic_on_find)?.path(); + let path = cache.at_path("dir/file", Some(false), gix_object::find::Never)?.path(); assert!(path.parent().unwrap().is_dir(), "directory is still present"); assert!(!path.exists(), "it won't create the file"); assert_eq!(cache.statistics().delegate.num_mkdir_calls, 1); @@ -77,7 +72,7 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R let relative_path = format!("{dirname}/file"); assert_eq!( cache - .at_path(&relative_path, Some(false), panic_on_find) + .at_path(&relative_path, Some(false), gix_object::find::Never) .unwrap_err() .kind(), std::io::ErrorKind::AlreadyExists @@ -97,7 +92,9 @@ fn symlinks_or_files_in_path_are_forbidden_or_unlinked_when_forced() -> crate::R *unlink_on_collision = true; } let relative_path = format!("{dirname}/file"); - let path = cache.at_path(&relative_path, Some(false), panic_on_find)?.path(); + let path = cache + .at_path(&relative_path, Some(false), gix_object::find::Never)? + .path(); assert!(path.parent().unwrap().is_dir(), "directory was forcefully created"); assert!(!path.exists()); } diff --git a/gix-worktree/tests/worktree/stack/ignore.rs b/gix-worktree/tests/worktree/stack/ignore.rs index 0d0b7523e4f..6dbcecb5cb8 100644 --- a/gix-worktree/tests/worktree/stack/ignore.rs +++ b/gix-worktree/tests/worktree/stack/ignore.rs @@ -1,5 +1,4 @@ use bstr::{BStr, ByteSlice}; -use gix_object::FindExt; use gix_worktree::{stack::state::ignore::Source, Stack}; use crate::hex_to_id; @@ -51,16 +50,22 @@ fn exclude_by_dir_is_handled_just_like_git() { let expectations = IgnoreExpectations { lines: baseline.lines(), }; + struct FindError; + impl gix_object::Find for FindError { + fn try_find<'a>( + &self, + _id: &gix_hash::oid, + _buffer: &'a mut Vec, + ) -> Result>, gix_object::find::Error> { + Err(std::io::Error::new(std::io::ErrorKind::Other, "unreachable").into()) + } + } for (relative_entry, source_and_line) in expectations { let (source, line, expected_pattern) = source_and_line.expect("every value is matched"); let relative_path = gix_path::from_byte_slice(relative_entry); let is_dir = dir.join(relative_path).metadata().ok().map(|m| m.is_dir()); - let platform = cache - .at_entry(relative_entry, is_dir, |_oid, _buf| { - Err(std::io::Error::new(std::io::ErrorKind::Other, "unreachable")) - }) - .unwrap(); + let platform = cache.at_entry(relative_entry, is_dir, FindError).unwrap(); let match_ = platform.matching_exclude_pattern().expect("match all values"); let _is_excluded = platform.is_excluded(); assert_eq!( @@ -119,7 +124,7 @@ fn check_against_baseline() -> crate::Result { let relative_path = gix_path::from_byte_slice(relative_entry); let is_dir = worktree_dir.join(relative_path).metadata().ok().map(|m| m.is_dir()); - let platform = cache.at_entry(relative_entry, is_dir, |oid, buf| odb.find_blob(oid, buf))?; + let platform = cache.at_entry(relative_entry, is_dir, &odb)?; let match_ = platform.matching_exclude_pattern(); let is_excluded = platform.is_excluded();