Skip to content

Commit f3be6e3

Browse files
authored
Merge pull request GitoxideLabs#2119 from GitoxideLabs/improvements
various improvements
2 parents d8fbe1e + 5da38e5 commit f3be6e3

File tree

11 files changed

+296
-40
lines changed

11 files changed

+296
-40
lines changed

gitoxide-core/src/repository/status.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ fn print_index_entry_status(
220220
) -> std::io::Result<()> {
221221
let char_storage;
222222
let status = match status {
223-
EntryStatus::Conflict(conflict) => as_str(conflict),
223+
EntryStatus::Conflict { summary, entries: _ } => as_str(summary),
224224
EntryStatus::Change(change) => {
225225
char_storage = change_to_char(&change);
226226
std::str::from_utf8(std::slice::from_ref(&char_storage)).expect("valid ASCII")

gix-index/src/entry/flags.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ bitflags! {
66
/// In-memory flags.
77
///
88
/// Notably, not all of these will be persisted but can be used to aid all kinds of operations.
9-
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
9+
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
1010
pub struct Flags: u32 {
1111
// TODO: could we use the pathlen ourselves to save 8 bytes? And how to handle longer paths than that? 0 as sentinel maybe?
1212
/// The mask to obtain the length of the path associated with this entry, up to 4095 characters without extension.

gix-status/src/index_as_worktree/function.rs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use gix_features::parallel::{in_parallel_if, Reduce};
1111
use gix_filter::pipeline::convert::ToGitOutcome;
1212
use gix_object::FindExt;
1313

14+
use crate::index_as_worktree::types::ConflictIndexEntry;
1415
use crate::{
1516
index_as_worktree::{
1617
traits,
@@ -165,7 +166,7 @@ where
165166
return None;
166167
}
167168
Conflict::try_from_entry(all_entries, state.path_backing, absolute_entry_index, entry_path)
168-
.map(|(_conflict, offset)| offset)
169+
.map(|(_conflict, offset, _entries)| offset)
169170
});
170171
if let Some(entries_to_skip_as_conflict_originates_in_previous_chunk) = offset {
171172
// skip current entry as it's done, along with following conflict entries
@@ -287,10 +288,22 @@ impl<'index> State<'_, 'index> {
287288
}
288289
let status = if entry.stage_raw() != 0 {
289290
Ok(
290-
Conflict::try_from_entry(entries, self.path_backing, entry_index, path).map(|(conflict, offset)| {
291-
*outer_entry_index += offset; // let out loop skip over entries related to the conflict
292-
EntryStatus::Conflict(conflict)
293-
}),
291+
Conflict::try_from_entry(entries, self.path_backing, entry_index, path).map(
292+
|(conflict, offset, entries)| {
293+
*outer_entry_index += offset; // let out loop skip over entries related to the conflict
294+
EntryStatus::Conflict {
295+
summary: conflict,
296+
entries: Box::new({
297+
let mut a: [Option<ConflictIndexEntry>; 3] = Default::default();
298+
let src = entries.into_iter().map(|e| e.map(ConflictIndexEntry::from));
299+
for (a, b) in a.iter_mut().zip(src) {
300+
*a = b;
301+
}
302+
a
303+
}),
304+
}
305+
},
306+
),
294307
)
295308
} else {
296309
self.compute_status(entry, path, diff, submodule, objects)
@@ -622,20 +635,23 @@ impl Conflict {
622635
/// Also return the amount of extra-entries that were part of the conflict declaration (not counting the entry at `start_index`)
623636
///
624637
/// If for some reason entry at `start_index` isn't in conflicting state, `None` is returned.
625-
pub fn try_from_entry(
626-
entries: &[gix_index::Entry],
638+
///
639+
/// Return `(Self, num_consumed_entries, three_possibly_entries)`.
640+
pub fn try_from_entry<'entry>(
641+
entries: &'entry [gix_index::Entry],
627642
path_backing: &gix_index::PathStorageRef,
628643
start_index: usize,
629644
entry_path: &BStr,
630-
) -> Option<(Self, usize)> {
645+
) -> Option<(Self, usize, [Option<&'entry gix_index::Entry>; 3])> {
631646
use Conflict::*;
632647
let mut mask = None::<u8>;
648+
let mut seen: [Option<&gix_index::Entry>; 3] = Default::default();
633649

634-
let mut count = 0_usize;
635-
for stage in (start_index..(start_index + 3).min(entries.len())).filter_map(|idx| {
650+
let mut num_consumed_entries = 0_usize;
651+
for (stage, entry) in (start_index..(start_index + 3).min(entries.len())).filter_map(|idx| {
636652
let entry = &entries[idx];
637653
let stage = entry.stage_raw();
638-
(stage > 0 && entry.path_in(path_backing) == entry_path).then_some(stage)
654+
(stage > 0 && entry.path_in(path_backing) == entry_path).then_some((stage, entry))
639655
}) {
640656
// This could be `1 << (stage - 1)` but let's be specific.
641657
*mask.get_or_insert(0) |= match stage {
@@ -644,7 +660,8 @@ impl Conflict {
644660
3 => 0b100,
645661
_ => 0,
646662
};
647-
count += 1;
663+
num_consumed_entries = stage as usize - 1;
664+
seen[num_consumed_entries] = Some(entry);
648665
}
649666

650667
mask.map(|mask| {
@@ -659,7 +676,8 @@ impl Conflict {
659676
0b111 => BothModified,
660677
_ => unreachable!("BUG: bitshifts and typical entry layout doesn't allow for more"),
661678
},
662-
count - 1,
679+
num_consumed_entries,
680+
seen,
663681
)
664682
})
665683
}

gix-status/src/index_as_worktree/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Changes between an index and a worktree.
22
///
33
mod types;
4-
pub use types::{Change, Conflict, Context, EntryStatus, Error, Options, Outcome, VisitEntry};
4+
pub use types::{Change, Conflict, ConflictIndexEntry, Context, EntryStatus, Error, Options, Outcome, VisitEntry};
55

66
mod recorder;
77
pub use recorder::{Record, Recorder};

gix-status/src/index_as_worktree/types.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::sync::atomic::AtomicBool;
22

33
use bstr::{BStr, BString};
4+
use gix_index::entry;
45

56
/// The error returned by [index_as_worktree()`](crate::index_as_worktree()).
67
#[derive(Debug, thiserror::Error)]
@@ -144,11 +145,48 @@ pub enum Change<T = (), U = ()> {
144145
SubmoduleModification(U),
145146
}
146147

148+
/// Like [`gix_index::Entry`], but without disk-metadata.
149+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
150+
pub struct ConflictIndexEntry {
151+
/// The object id for this entry's ODB representation (assuming it's up-to-date with it).
152+
pub id: gix_hash::ObjectId,
153+
/// Additional flags for use in algorithms and for efficiently storing stage information, primarily
154+
/// to obtain the [stage](entry::Flags::stage()).
155+
pub flags: entry::Flags,
156+
/// The kind of item this entry represents - it's not all blobs in the index anymore.
157+
pub mode: entry::Mode,
158+
}
159+
160+
impl From<&gix_index::Entry> for ConflictIndexEntry {
161+
fn from(
162+
gix_index::Entry {
163+
stat: _,
164+
id,
165+
flags,
166+
mode,
167+
..
168+
}: &gix_index::Entry,
169+
) -> Self {
170+
ConflictIndexEntry {
171+
id: *id,
172+
flags: *flags,
173+
mode: *mode,
174+
}
175+
}
176+
}
177+
147178
/// Information about an entry.
148-
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
179+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
149180
pub enum EntryStatus<T = (), U = ()> {
150-
/// The entry is in a conflicting state, and we didn't collect any more information about it.
151-
Conflict(Conflict),
181+
/// The entry is in a conflicting state, and we provide all related entries along with a summary.
182+
Conflict {
183+
/// An analysis on the conflict itself based on the observed index entries.
184+
summary: Conflict,
185+
/// The entries from stage 1 to stage 3, where stage 1 is at index 0 and stage 3 at index 2.
186+
/// Note that when there are conflicts, there is no stage 0.
187+
/// Further, all entries are looking at the same path.
188+
entries: Box<[Option<ConflictIndexEntry>; 3]>,
189+
},
152190
/// There is no conflict and a change was discovered.
153191
Change(Change<T, U>),
154192
/// The entry didn't change, but its state caused extra work that can be avoided next time if its stats would be updated to the

gix-status/src/index_as_worktree_with_renames/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ pub(super) mod function {
460460
fn kind(&self) -> ChangeKind {
461461
match self {
462462
ModificationOrDirwalkEntry::Modification(m) => match &m.status {
463-
EntryStatus::Conflict(_) | EntryStatus::IntentToAdd | EntryStatus::NeedsUpdate(_) => {
463+
EntryStatus::Conflict { .. } | EntryStatus::IntentToAdd | EntryStatus::NeedsUpdate(_) => {
464464
ChangeKind::Modification
465465
}
466466
EntryStatus::Change(c) => match c {

gix-status/src/index_as_worktree_with_renames/types.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub enum Sorting {
3737
}
3838

3939
/// Provide additional information collected during the runtime of [`index_as_worktree_with_renames()`](crate::index_as_worktree_with_renames()).
40-
#[derive(Clone, Debug, Default, PartialEq)]
40+
#[derive(Clone, Debug, Default)]
4141
pub struct Outcome {
4242
/// The outcome of the modification check of tracked files.
4343
pub tracked_file_modification: crate::index_as_worktree::Outcome,
@@ -49,7 +49,7 @@ pub struct Outcome {
4949
}
5050

5151
/// Either an index entry for renames or another directory entry in case of copies.
52-
#[derive(Clone, PartialEq, Debug)]
52+
#[derive(Clone, Debug)]
5353
pub enum RewriteSource<'index, ContentChange, SubmoduleStatus> {
5454
/// The source originates in the index and is detected as missing in the working tree.
5555
/// This can also happen for copies.
@@ -86,7 +86,7 @@ pub enum RewriteSource<'index, ContentChange, SubmoduleStatus> {
8686
}
8787

8888
/// An 'entry' in the sense of a merge of modified tracked files and results from a directory walk.
89-
#[derive(Clone, PartialEq, Debug)]
89+
#[derive(Clone, Debug)]
9090
pub enum Entry<'index, ContentChange, SubmoduleStatus> {
9191
/// A tracked file was modified, and index-specific information is passed.
9292
Modification {
@@ -218,7 +218,7 @@ impl<ContentChange, SubmoduleStatus> Entry<'_, ContentChange, SubmoduleStatus> {
218218
pub fn summary(&self) -> Option<Summary> {
219219
Some(match self {
220220
Entry::Modification {
221-
status: EntryStatus::Conflict(_),
221+
status: EntryStatus::Conflict { .. },
222222
..
223223
} => Summary::Conflict,
224224
Entry::Modification {

0 commit comments

Comments
 (0)