Skip to content

Commit e079250

Browse files
committedAug 21, 2024··
feat: add objects::tree::diff::Platform::stats() to quickly obtain diff-stats.
This function is inspired by `git2` which also makes it very simple to obtain.
1 parent b291de0 commit e079250

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed
 

Diff for: ‎gix/src/object/tree/diff/mod.rs

+68-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl<'a, 'repo> Platform<'a, 'repo> {
9191
}
9292

9393
/// Provide `None` to disable rewrite tracking entirely, or pass `Some(<configuration>)` to control to
94-
/// what extend rename and copy tracking is performed.
94+
/// what extent rename and copy tracking is performed.
9595
///
9696
/// Note that by default, the git configuration determines rewrite tracking and git defaults are used
9797
/// if nothing is configured, which turns rename tracking with 50% similarity on, while not tracking copies at all.
@@ -101,6 +101,73 @@ impl<'a, 'repo> Platform<'a, 'repo> {
101101
}
102102
}
103103

104+
/// Provide aggregated information of a diff between two trees.
105+
#[derive(Default, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
106+
#[doc(alias = "DiffStats", alias = "git2")]
107+
pub struct Stats {
108+
/// The total amount of lines added in the between blobs of the two trees.
109+
#[doc(alias = "insertions", alias = "git2")]
110+
pub lines_added: u64,
111+
/// The total amount of lines removed in the between blobs of the two trees.
112+
#[doc(alias = "deletions", alias = "git2")]
113+
pub lines_removed: u64,
114+
/// The number of files that contributed to these statistics as they were added, removed or modified.
115+
pub files_changed: u64,
116+
}
117+
118+
///
119+
#[allow(clippy::empty_docs)]
120+
pub mod stats {
121+
/// The error returned by [`stats()`](super::Platform::stats()).
122+
#[derive(Debug, thiserror::Error)]
123+
#[allow(missing_docs)]
124+
pub enum Error {
125+
#[error(transparent)]
126+
CreateResourceCache(#[from] crate::repository::diff::resource_cache::Error),
127+
#[error(transparent)]
128+
ForEachChange(#[from] crate::object::tree::diff::for_each::Error),
129+
}
130+
}
131+
132+
/// Convenience
133+
impl<'a, 'repo> Platform<'a, 'repo> {
134+
/// Calculate statistics about the lines of the diff between our current and the `other` tree.
135+
///
136+
/// ### Performance Notes
137+
///
138+
/// Be sure to forcefully disable [`track_rewrites(None)`](Self::track_rewrites) to avoid
139+
/// rename tracking, an operation that doesn't affect the statistics currently.
140+
/// As diffed resources aren't cached, if highly repetitive blobs are expected, performance
141+
/// may be diminished. In real-world scenarios where blobs are mostly unique, that's not an issue though.
142+
pub fn stats(&mut self, other: &Tree<'_>) -> Result<Stats, stats::Error> {
143+
// let (mut number_of_files, mut lines_added, mut lines_removed) = (0, 0, 0);
144+
let mut resource_cache = self.lhs.repo.diff_resource_cache_for_tree_diff()?;
145+
146+
let (mut files_changed, mut lines_added, mut lines_removed) = (0, 0, 0);
147+
self.for_each_to_obtain_tree(other, |change| {
148+
if let Some(counts) = change
149+
.diff(&mut resource_cache)
150+
.ok()
151+
.and_then(|mut platform| platform.line_counts().ok())
152+
.flatten()
153+
{
154+
files_changed += 1;
155+
lines_added += counts.insertions as u64;
156+
lines_removed += counts.removals as u64;
157+
}
158+
159+
resource_cache.clear_resource_cache();
160+
Ok::<_, std::convert::Infallible>(Action::Continue)
161+
})?;
162+
163+
Ok(Stats {
164+
files_changed,
165+
lines_added,
166+
lines_removed,
167+
})
168+
}
169+
}
170+
104171
///
105172
#[allow(clippy::empty_docs)]
106173
pub mod for_each;

Diff for: ‎gix/tests/object/tree/diff.rs

+11
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ fn changes_against_tree_modified() -> crate::Result {
7272
Ok(Default::default())
7373
})?;
7474
assert_eq!(i, 3);
75+
76+
assert_eq!(
77+
from.changes()?.stats(&to)?,
78+
gix::object::tree::diff::Stats {
79+
lines_added: 2,
80+
lines_removed: 0,
81+
files_changed: 2,
82+
},
83+
"two files with one added line each"
84+
);
85+
7586
Ok(())
7687
}
7788

0 commit comments

Comments
 (0)
Please sign in to comment.