use gix_diff::tree;
use crate::{Id, Result, Tree, bstr::BStr};
pub type Action = std::ops::ControlFlow<()>;
pub use gix_diff::tree_with_rewrites::Change as ChangeDetached;
#[derive(Debug, Clone, Copy)]
pub enum Change<'a, 'old, 'new> {
Addition {
location: &'a BStr,
entry_mode: gix_object::tree::EntryMode,
relation: Option<tree::visit::Relation>,
id: Id<'new>,
},
Deletion {
location: &'a BStr,
entry_mode: gix_object::tree::EntryMode,
relation: Option<tree::visit::Relation>,
id: Id<'old>,
},
Modification {
location: &'a BStr,
previous_entry_mode: gix_object::tree::EntryMode,
previous_id: Id<'old>,
entry_mode: gix_object::tree::EntryMode,
id: Id<'new>,
},
Rewrite {
source_location: &'a BStr,
source_relation: Option<tree::visit::Relation>,
source_entry_mode: gix_object::tree::EntryMode,
source_id: Id<'old>,
diff: Option<gix_diff::blob::DiffLineStats>,
entry_mode: gix_object::tree::EntryMode,
location: &'a BStr,
id: Id<'new>,
relation: Option<tree::visit::Relation>,
copy: bool,
},
}
pub mod change;
impl<'repo> Tree<'repo> {
#[doc(alias = "diff_tree_to_tree", alias = "git2")]
pub fn changes<'a>(&'a self) -> Result<Platform<'a, 'repo>> {
Ok(Platform {
state: Default::default(),
lhs: self,
options: crate::diff::Options::from_configuration(&self.repo.config)?,
})
}
}
#[derive(Clone)]
pub struct Platform<'a, 'repo> {
state: gix_diff::tree::State,
lhs: &'a Tree<'repo>,
options: crate::diff::Options,
}
impl Platform<'_, '_> {
pub fn options(&mut self, change_opts: impl FnOnce(&mut crate::diff::Options)) -> &mut Self {
change_opts(&mut self.options);
self
}
}
#[derive(Default, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[doc(alias = "DiffStats", alias = "git2")]
pub struct Stats {
#[doc(alias = "insertions", alias = "git2")]
pub lines_added: u64,
#[doc(alias = "deletions", alias = "git2")]
pub lines_removed: u64,
pub files_changed: u64,
}
impl Platform<'_, '_> {
pub fn stats(&mut self, other: &Tree<'_>) -> Result<Stats> {
let mut resource_cache = self.lhs.repo.diff_resource_cache_for_tree_diff()?;
let (mut files_changed, mut lines_added, mut lines_removed) = (0, 0, 0);
self.for_each_to_obtain_tree(other, |change| {
if let Some(counts) = change
.diff(&mut resource_cache)
.ok()
.and_then(|mut platform| platform.line_counts().ok())
.flatten()
{
files_changed += 1;
lines_added += u64::from(counts.insertions);
lines_removed += u64::from(counts.removals);
}
resource_cache.clear_resource_cache_keep_allocation();
Ok::<_, gix_error::Exn>(std::ops::ControlFlow::Continue(()))
})?;
Ok(Stats {
files_changed,
lines_added,
lines_removed,
})
}
}
pub mod for_each;