Skip to content

Commit b55a8d5

Browse files
committed
feat!: add entries-relative index to each change.
That way it's possible to lookup other, surrounding entries in case of conflicts or easily find entries that didn't change.
1 parent de66b4c commit b55a8d5

File tree

6 files changed

+131
-52
lines changed

6 files changed

+131
-52
lines changed

gix-status/src/index_as_worktree/function.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::slice::ChunksMut;
12
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
23
use std::{io, marker::PhantomData, path::Path};
34

@@ -19,7 +20,7 @@ use crate::{
1920

2021
/// Calculates the changes that need to be applied to an `index` to match the state of the `worktree` and makes them
2122
/// observable in `collector`, along with information produced by `compare` which gets to see blobs that may have changes, and
22-
/// `submodule` which can take a look at submodules in detail to produce status information.
23+
/// `submodule` which can take a look at submodules in detail to produce status information (BASE version if its conflicting).
2324
/// `options` are used to configure the operation.
2425
///
2526
/// Note that `index` is updated with the latest seen stat information from the worktree, and its timestamp is adjusted to
@@ -85,6 +86,7 @@ where
8586
);
8687
let (entries, path_backing) = index.entries_mut_and_pathbacking();
8788
let mut num_entries = entries.len();
89+
let entry_index_offset = range.start;
8890
let entries = &mut entries[range];
8991

9092
let _span = gix_features::trace::detail!("gix_status::index_as_worktree",
@@ -137,14 +139,21 @@ where
137139
};
138140
in_parallel_if(
139141
|| true, // TODO: heuristic: when is parallelization not worth it? Git says 500 items per thread, but to 20 threads, we can be more fine-grained though.
140-
gix_features::interrupt::Iter::new(entries.chunks_mut(chunk_size), should_interrupt),
142+
gix_features::interrupt::Iter::new(
143+
OffsetIter {
144+
inner: entries.chunks_mut(chunk_size),
145+
offset: entry_index_offset,
146+
},
147+
should_interrupt,
148+
),
141149
thread_limit,
142150
new_state,
143-
|entries, (state, blobdiff, submdule, find, pathspec)| {
151+
|(entry_offset, entries), (state, blobdiff, submdule, find, pathspec)| {
144152
entries
145153
.iter_mut()
146-
.filter_map(|entry| {
147-
let res = state.process(entry, pathspec, blobdiff, submdule, find);
154+
.enumerate()
155+
.filter_map(|(entry_index, entry)| {
156+
let res = state.process(entry, entry_offset + entry_index, pathspec, blobdiff, submdule, find);
148157
count.fetch_add(1, Ordering::Relaxed);
149158
res
150159
})
@@ -198,12 +207,22 @@ struct State<'a, 'b> {
198207
odb_reads: &'a AtomicUsize,
199208
}
200209

201-
type StatusResult<'index, T, U> = Result<(&'index gix_index::Entry, &'index BStr, Option<Change<T, U>>, bool), Error>;
210+
type StatusResult<'index, T, U> = Result<
211+
(
212+
&'index gix_index::Entry,
213+
usize,
214+
&'index BStr,
215+
Option<Change<T, U>>,
216+
bool,
217+
),
218+
Error,
219+
>;
202220

203221
impl<'index> State<'_, 'index> {
204222
fn process<T, U, Find, E1, E2>(
205223
&mut self,
206224
entry: &'index mut gix_index::Entry,
225+
entry_index: usize,
207226
pathspec: &mut impl Pathspec,
208227
diff: &mut impl CompareBlobs<Output = T>,
209228
submodule: &mut impl SubmoduleStatus<Output = U, Error = E2>,
@@ -234,7 +253,7 @@ impl<'index> State<'_, 'index> {
234253
return None;
235254
}
236255
let status = self.compute_status(&mut *entry, path, diff, submodule, find);
237-
Some(status.map(move |status| (&*entry, path, status, conflict)))
256+
Some(status.map(move |status| (&*entry, entry_index, path, status, conflict)))
238257
}
239258

240259
/// # On how racy-git is handled here
@@ -412,8 +431,8 @@ impl<'index, T, U, C: VisitEntry<'index, ContentChange = T, SubmoduleStatus = U>
412431

413432
fn feed(&mut self, items: Self::Input) -> Result<Self::FeedProduce, Self::Error> {
414433
for item in items {
415-
let (entry, path, change, conflict) = item?;
416-
self.collector.visit_entry(entry, path, change, conflict);
434+
let (entry, entry_index, path, change, conflict) = item?;
435+
self.collector.visit_entry(entry, entry_index, path, change, conflict);
417436
}
418437
Ok(())
419438
}
@@ -511,3 +530,19 @@ where
511530
Ok(out)
512531
}
513532
}
533+
534+
struct OffsetIter<'a, T> {
535+
inner: ChunksMut<'a, T>,
536+
offset: usize,
537+
}
538+
539+
impl<'a, T> Iterator for OffsetIter<'a, T> {
540+
type Item = (usize, &'a mut [T]);
541+
542+
fn next(&mut self) -> Option<Self::Item> {
543+
let block = self.inner.next()?;
544+
let offset = self.offset;
545+
self.offset += block.len();
546+
Some((offset, block))
547+
}
548+
}

gix-status/src/index_as_worktree/recorder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use crate::index_as_worktree::{Change, VisitEntry};
1010
pub struct Record<'index, T, U> {
1111
/// The index entry that is changed.
1212
pub entry: &'index index::Entry,
13+
/// The index of the `entry` relative to all entries in the input index.
14+
pub entry_index: usize,
1315
/// The path to the entry.
1416
pub relative_path: &'index BStr,
1517
/// The change itself, or `None` if there is only a conflict.
@@ -32,13 +34,15 @@ impl<'index, T: Send, U: Send> VisitEntry<'index> for Recorder<'index, T, U> {
3234
fn visit_entry(
3335
&mut self,
3436
entry: &'index index::Entry,
37+
entry_index: usize,
3538
rela_path: &'index BStr,
3639
change: Option<Change<Self::ContentChange, Self::SubmoduleStatus>>,
3740
conflict: bool,
3841
) {
3942
if conflict || change.is_some() {
4043
self.records.push(Record {
4144
entry,
45+
entry_index,
4246
relative_path: rela_path,
4347
change,
4448
conflict,

gix-status/src/index_as_worktree/types.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,13 @@ pub trait VisitEntry<'index> {
118118
type ContentChange;
119119
/// Data obtained when checking the submodule status.
120120
type SubmoduleStatus;
121-
/// Observe the `change` of `entry` at the repository-relative `rela_path`, indicating whether
122-
/// or not it has a `conflict`.
121+
/// Observe the `change` of `entry` at the repository-relative `rela_path` at `entry_index`
122+
/// (relative to the complete list of all index entries), indicating whether or not it has a `conflict`.
123123
/// If `change` is `None`, there is no change.
124124
fn visit_entry(
125125
&mut self,
126126
entry: &'index gix_index::Entry,
127+
entry_index: usize,
127128
rela_path: &'index BStr,
128129
change: Option<Change<Self::ContentChange, Self::SubmoduleStatus>>,
129130
conflict: bool,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:c2d7b75f62872a98ad670d1239e5ff6867b004a84ffacb050c1f4bc06b5a1d17
3-
size 14876
2+
oid sha256:18a83500a44dbb5ab3865281645d45f8a81d469cdc7a719c2bb93e92f2fac00e
3+
size 16940

gix-status/tests/fixtures/status_submodule.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,17 @@ cp -R no-change empty-dir-no-change
3232
rm -Rf m1
3333
mkdir m1
3434
)
35+
36+
cp -R no-change conflict
37+
(cd conflict
38+
(cd m1
39+
git checkout @~1
40+
)
41+
42+
git commit -am "change submodule head"
43+
git checkout -b other @~1
44+
git rm -rf m1
45+
git commit -m "removed submodule"
46+
47+
git merge main || :
48+
)

0 commit comments

Comments
 (0)