Skip to content

Commit

Permalink
change!: use gix-object::Find trait
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Nov 5, 2023
1 parent a81514f commit 7407fec
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 49 deletions.
81 changes: 36 additions & 45 deletions gix-status/src/index_as_worktree/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bstr::BStr;
use filetime::FileTime;
use gix_features::parallel::{in_parallel_if, Reduce};
use gix_filter::pipeline::convert::ToGitOutcome;
use gix_object::FindExt;

use crate::index_as_worktree::traits::read_data::Stream;
use crate::index_as_worktree::{Conflict, EntryStatus};
Expand All @@ -31,6 +32,7 @@ use crate::{
/// `should_interrupt` can be used to stop all processing.
/// `filter` is used to convert worktree files back to their internal git representation. For this to be correct,
/// [`Options::attributes`] must be configured as well.
/// `objects` is used to access the version of an object in the object database for direct comparison.
///
/// **It's important to note that the `index` should have its [timestamp updated](gix_index::State::set_timestamp()) with a timestamp
/// from just before making this call *if* [entries were updated](Outcome::entries_to_update)**
Expand All @@ -45,13 +47,13 @@ use crate::{
/// Thus some care has to be taken to do the right thing when letting the index match the worktree by evaluating the changes observed
/// by the `collector`.
#[allow(clippy::too_many_arguments)]
pub fn index_as_worktree<'index, T, U, Find, E1, E2>(
pub fn index_as_worktree<'index, T, U, Find, E>(
index: &'index gix_index::State,
worktree: &Path,
collector: &mut impl VisitEntry<'index, ContentChange = T, SubmoduleStatus = U>,
compare: impl CompareBlobs<Output = T> + Send + Clone,
submodule: impl SubmoduleStatus<Output = U, Error = E2> + Send + Clone,
find: Find,
submodule: impl SubmoduleStatus<Output = U, Error = E> + Send + Clone,
objects: Find,
progress: &mut dyn gix_features::progress::Progress,
pathspec: impl Pathspec + Send + Clone,
filter: gix_filter::Pipeline,
Expand All @@ -61,9 +63,8 @@ pub fn index_as_worktree<'index, T, U, Find, E1, E2>(
where
T: Send,
U: Send,
E1: std::error::Error + Send + Sync + 'static,
E2: std::error::Error + Send + Sync + 'static,
Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec<u8>) -> Result<gix_object::BlobRef<'a>, E1> + Send + Clone,
E: std::error::Error + Send + Sync + 'static,
Find: gix_object::Find + Send + Clone,
{
// the order is absolutely critical here we use the old timestamp to detect racy index entries
// (modified at or after the last index update) during the index update we then set those
Expand Down Expand Up @@ -135,7 +136,7 @@ where
},
compare,
submodule,
find,
objects,
pathspec,
)
}
Expand All @@ -151,7 +152,7 @@ where
),
thread_limit,
new_state,
|(entry_offset, chunk_entries), (state, blobdiff, submdule, find, pathspec)| {
|(entry_offset, chunk_entries), (state, blobdiff, submdule, objects, pathspec)| {
let all_entries = index.entries();
let mut out = Vec::new();
let mut idx = 0;
Expand Down Expand Up @@ -181,7 +182,7 @@ where
pathspec,
blobdiff,
submdule,
find,
objects,
&mut idx,
);
idx += 1;
Expand Down Expand Up @@ -244,21 +245,20 @@ type StatusResult<'index, T, U> = Result<(&'index gix_index::Entry, usize, &'ind

impl<'index> State<'_, 'index> {
#[allow(clippy::too_many_arguments)]
fn process<T, U, Find, E1, E2>(
fn process<T, U, Find, E>(
&mut self,
entries: &'index [gix_index::Entry],
entry: &'index gix_index::Entry,
entry_index: usize,
pathspec: &mut impl Pathspec,
diff: &mut impl CompareBlobs<Output = T>,
submodule: &mut impl SubmoduleStatus<Output = U, Error = E2>,
find: &mut Find,
submodule: &mut impl SubmoduleStatus<Output = U, Error = E>,
objects: &Find,
outer_entry_index: &mut usize,
) -> Option<StatusResult<'index, T, U>>
where
E1: std::error::Error + Send + Sync + 'static,
E2: std::error::Error + Send + Sync + 'static,
Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec<u8>) -> Result<gix_object::BlobRef<'a>, E1>,
E: std::error::Error + Send + Sync + 'static,
Find: gix_object::Find,
{
if entry.flags.intersects(
gix_index::entry::Flags::UPTODATE
Expand All @@ -282,7 +282,7 @@ impl<'index> State<'_, 'index> {
}),
)
} else {
self.compute_status(entry, path, diff, submodule, find)
self.compute_status(entry, path, diff, submodule, objects)
};
match status {
Ok(None) => None,
Expand Down Expand Up @@ -330,18 +330,17 @@ impl<'index> State<'_, 'index> {
/// which is a constant.
///
/// Adapted from [here](https://github.com/Byron/gitoxide/pull/805#discussion_r1164676777).
fn compute_status<T, U, Find, E1, E2>(
fn compute_status<T, U, Find, E>(
&mut self,
entry: &gix_index::Entry,
rela_path: &BStr,
diff: &mut impl CompareBlobs<Output = T>,
submodule: &mut impl SubmoduleStatus<Output = U, Error = E2>,
find: &mut Find,
submodule: &mut impl SubmoduleStatus<Output = U, Error = E>,
objects: &Find,
) -> Result<Option<EntryStatus<T, U>>, Error>
where
E1: std::error::Error + Send + Sync + 'static,
E2: std::error::Error + Send + Sync + 'static,
Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec<u8>) -> Result<gix_object::BlobRef<'a>, E1>,
E: std::error::Error + Send + Sync + 'static,
Find: gix_object::Find,
{
let worktree_path = match self.path_stack.verified_path(gix_path::from_bstr(rela_path).as_ref()) {
Ok(path) => path,
Expand Down Expand Up @@ -423,7 +422,7 @@ impl<'index> State<'_, 'index> {
attr_stack: &mut self.attr_stack,
options: self.options,
id: &entry.id,
find,
objects,
worktree_reads: self.worktree_reads,
worktree_bytes: self.worktree_bytes,
odb_reads: self.odb_reads,
Expand Down Expand Up @@ -478,10 +477,9 @@ impl<'index, T, U, C: VisitEntry<'index, ContentChange = T, SubmoduleStatus = U>
}
}

struct ReadDataImpl<'a, Find, E>
struct ReadDataImpl<'a, Find>
where
E: std::error::Error + Send + Sync + 'static,
Find: for<'b> FnMut(&gix_hash::oid, &'b mut Vec<u8>) -> Result<gix_object::BlobRef<'b>, E>,
Find: gix_object::Find,
{
buf: &'a mut Vec<u8>,
path: &'a Path,
Expand All @@ -492,29 +490,26 @@ where
attr_stack: &'a mut gix_worktree::Stack,
options: &'a Options,
id: &'a gix_hash::oid,
find: Find,
objects: Find,
worktree_bytes: &'a AtomicU64,
worktree_reads: &'a AtomicUsize,
odb_bytes: &'a AtomicU64,
odb_reads: &'a AtomicUsize,
}

impl<'a, Find, E> traits::ReadData<'a> for ReadDataImpl<'a, Find, E>
impl<'a, Find> traits::ReadData<'a> for ReadDataImpl<'a, Find>
where
E: std::error::Error + Send + Sync + 'static,
Find: for<'b> FnMut(&gix_hash::oid, &'b mut Vec<u8>) -> Result<gix_object::BlobRef<'b>, E>,
Find: gix_object::Find,
{
fn read_blob(mut self) -> Result<&'a [u8], Error> {
(self.find)(self.id, self.buf)
.map(|b| {
self.odb_reads.fetch_add(1, Ordering::Relaxed);
self.odb_bytes.fetch_add(b.data.len() as u64, Ordering::Relaxed);
b.data
})
.map_err(move |err| Error::Find(Box::new(err)))
fn read_blob(self) -> Result<&'a [u8], Error> {
Ok(self.objects.find_blob(self.id, self.buf).map(|b| {
self.odb_reads.fetch_add(1, Ordering::Relaxed);
self.odb_bytes.fetch_add(b.data.len() as u64, Ordering::Relaxed);
b.data
})?)
}

fn stream_worktree_file(mut self) -> Result<Stream<'a>, Error> {
fn stream_worktree_file(self) -> Result<Stream<'a>, Error> {
self.buf.clear();
// symlinks are only stored as actual symlinks if the FS supports it otherwise they are just
// normal files with their content equal to the linked path (so can be read normally)
Expand All @@ -534,7 +529,7 @@ where
}
} else {
self.buf.clear();
let platform = self.attr_stack.at_entry(self.rela_path, Some(false), &mut self.find)?;
let platform = self.attr_stack.at_entry(self.rela_path, Some(false), &self.objects)?;
let file = std::fs::File::open(self.path)?;
let out = self
.filter
Expand All @@ -544,11 +539,7 @@ where
&mut |_path, attrs| {
platform.matching_attributes(attrs);
},
&mut |buf| {
(self.find)(self.id, buf)
.map(|_| Some(()))
.map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync + 'static>)
},
&mut |buf| Ok(self.objects.find_blob(self.id, buf).map(|_| Some(()))?),
)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
let len = match out {
Expand Down
2 changes: 1 addition & 1 deletion gix-status/src/index_as_worktree/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub enum Error {
#[error("IO error while writing blob or reading file metadata or changing filetype")]
Io(#[from] std::io::Error),
#[error("Failed to obtain blob from object database")]
Find(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
Find(#[from] gix_object::find::existing_object::Error),
#[error("Could not determine status for submodule at '{rela_path}'")]
SubmoduleStatus {
rela_path: BString,
Expand Down
6 changes: 3 additions & 3 deletions gix-status/tests/status/index_as_worktree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn fixture_filtered_detailed(
&mut recorder,
FastEq,
SubmoduleStatusMock { dirty: submodule_dirty },
|_, _| Ok::<_, std::convert::Infallible>(gix_object::BlobRef { data: &[] }),
gix_object::find::Never,
&mut gix_features::progress::Discard,
Pathspec(search),
Default::default(),
Expand Down Expand Up @@ -615,7 +615,7 @@ fn racy_git() {
&mut recorder,
counter.clone(),
SubmoduleStatusMock { dirty: false },
|_, _| Err(std::io::Error::new(std::io::ErrorKind::Other, "no odb access expected")),
gix_object::find::Never,
&mut gix_features::progress::Discard,
Pathspec::default(),
Default::default(),
Expand Down Expand Up @@ -654,7 +654,7 @@ fn racy_git() {
&mut recorder,
counter,
SubmoduleStatusMock { dirty: false },
|_, _| Err(std::io::Error::new(std::io::ErrorKind::Other, "no odb access expected")),
gix_object::find::Never,
&mut gix_features::progress::Discard,
Pathspec::default(),
Default::default(),
Expand Down

0 comments on commit 7407fec

Please sign in to comment.