mirror of
https://seed.radicle.dev/rad:z39mP9rQAaGmERfUMPULfPUi473tY.git
synced 2026-10-27 15:20:38 +08:00
73 lines
2.0 KiB
Rust
73 lines
2.0 KiB
Rust
use std::fs;
|
|
use std::path::Path;
|
|
|
|
use radicle::git;
|
|
use radicle::git::Oid;
|
|
|
|
/// Get the diff stats between two commits.
|
|
/// Should match the default output of `git diff <old> <new> --stat` exactly.
|
|
pub fn diff_stats(
|
|
repo: &git::raw::Repository,
|
|
old: &Oid,
|
|
new: &Oid,
|
|
) -> Result<git::raw::DiffStats, git::raw::Error> {
|
|
let old = repo.find_commit(**old)?;
|
|
let new = repo.find_commit(**new)?;
|
|
let old_tree = old.tree()?;
|
|
let new_tree = new.tree()?;
|
|
let mut diff = repo.diff_tree_to_tree(Some(&old_tree), Some(&new_tree), None)?;
|
|
let mut find_opts = git::raw::DiffFindOptions::new();
|
|
|
|
diff.find_similar(Some(&mut find_opts))?;
|
|
diff.stats()
|
|
}
|
|
|
|
/// Blob returned by the [`Repo`] trait.
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
pub enum Blob {
|
|
Binary,
|
|
Empty,
|
|
Plain(Vec<u8>),
|
|
}
|
|
|
|
/// A repository of Git blobs.
|
|
pub trait Repo {
|
|
/// Lookup a blob from the repo.
|
|
fn blob(&self, oid: git::Oid) -> Result<Blob, git::raw::Error>;
|
|
/// Lookup a file in the workdir.
|
|
fn file(&self, path: &Path) -> Option<Blob>;
|
|
}
|
|
|
|
impl Repo for git::raw::Repository {
|
|
fn blob(&self, oid: git::Oid) -> Result<Blob, git::raw::Error> {
|
|
let blob = self.find_blob(*oid)?;
|
|
|
|
if blob.is_binary() {
|
|
Ok(Blob::Binary)
|
|
} else {
|
|
let content = blob.content();
|
|
|
|
if content.is_empty() {
|
|
Ok(Blob::Empty)
|
|
} else {
|
|
Ok(Blob::Plain(blob.content().to_vec()))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn file(&self, path: &Path) -> Option<Blob> {
|
|
self.workdir()
|
|
.and_then(|dir| fs::read(dir.join(path)).ok())
|
|
.map(|content| {
|
|
// A file is considered binary if there is a zero byte in the first 8 kilobytes
|
|
// of the file. This is the same heuristic Git uses.
|
|
let binary = content.iter().take(8192).any(|b| *b == 0);
|
|
if binary {
|
|
Blob::Binary
|
|
} else {
|
|
Blob::Plain(content)
|
|
}
|
|
})
|
|
}
|
|
}
|