Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions src/git/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl GitRepo {
let meta = if let Some(cached) = commit_cache.get(&commit_id) {
cached.clone()
} else {
let commit = self.repo.find_commit(commit_id)?;
let commit = self.find_commit_with_context(commit_id, None)?;
let secs = commit.time()?.seconds;
let timestamp = Utc
.timestamp_opt(secs, 0)
Expand Down Expand Up @@ -204,9 +204,10 @@ impl GitRepo {
parent_id: Option<ObjectId>,
binary: bool,
) -> Result<CommitStats> {
let commit_tree = self.repo.find_commit(commit_id)?.tree()?;
let commit = self.find_commit_with_context(commit_id, Some(&commit_info.id))?;
let commit_tree = commit.tree()?;
let parent_tree = if let Some(pid) = parent_id {
Some(self.repo.find_commit(pid)?.tree()?)
Some(self.find_commit_with_context(pid, Some(&commit_info.id))?.tree()?)
} else {
None
};
Expand All @@ -215,7 +216,7 @@ impl GitRepo {
.diff_tree_to_tree(parent_tree.as_ref(), Some(&commit_tree), None)?;
let mut files = Vec::new();
for change in changes {
self.handle_change(change, binary, &mut files)?;
self.handle_change(change, binary, &mut files, &commit_info.id)?;
}

Ok(CommitStats {
Expand All @@ -229,10 +230,11 @@ impl GitRepo {
change: ChangeDetached,
binary: bool,
files: &mut Vec<FileStats>,
from_commit: &str,
) -> Result<()> {
match change {
ChangeDetached::Addition { id, location, .. } => {
let (is_binary, lines, _) = self.inspect_object(id)?;
let (is_binary, lines, _) = self.inspect_object(id, Some(from_commit))?;
if binary || !is_binary {
files.push(FileStats {
path: location.to_string(),
Expand All @@ -243,7 +245,7 @@ impl GitRepo {
}
}
ChangeDetached::Deletion { id, location, .. } => {
let (is_binary, lines, _) = self.inspect_object(id)?;
let (is_binary, lines, _) = self.inspect_object(id, Some(from_commit))?;
if binary || !is_binary {
files.push(FileStats {
path: location.to_string(),
Expand All @@ -259,8 +261,8 @@ impl GitRepo {
location,
..
} => {
let (old_is_binary, _, old_obj) = self.inspect_object(previous_id)?;
let (new_is_binary, _, new_obj) = self.inspect_object(id)?;
let (old_is_binary, _, old_obj) = self.inspect_object(previous_id, Some(from_commit))?;
let (new_is_binary, _, new_obj) = self.inspect_object(id, Some(from_commit))?;
let is_binary = old_is_binary || new_is_binary;
if binary || !is_binary {
let (added, deleted) = if is_binary {
Expand All @@ -284,8 +286,8 @@ impl GitRepo {
copy,
..
} => {
let (old_is_binary, _, old_obj) = self.inspect_object(source_id)?;
let (new_is_binary, _, new_obj) = self.inspect_object(id)?;
let (old_is_binary, _, old_obj) = self.inspect_object(source_id, Some(from_commit))?;
let (new_is_binary, _, new_obj) = self.inspect_object(id, Some(from_commit))?;
let is_binary = old_is_binary || new_is_binary;
if binary || !is_binary {
let (added, deleted) = if is_binary {
Expand All @@ -311,8 +313,14 @@ impl GitRepo {
Ok(())
}

fn inspect_object(&self, id: gix::ObjectId) -> Result<(bool, u32, gix::Object<'_>)> {
let obj = self.repo.find_object(id)?;
fn inspect_object(&self, id: gix::ObjectId, from_commit: Option<&str>) -> Result<(bool, u32, gix::Object<'_>)> {
let obj = self.repo.find_object(id).map_err(|e| {
if let Some(from) = from_commit {
GmapError::Other(format!("Object find error: {} (referenced from commit {})", e, from))
} else {
GmapError::from(e)
}
})?;
let is_binary = self.is_binary_object(&obj);
let lines = if is_binary {
0
Expand All @@ -322,6 +330,16 @@ impl GitRepo {
Ok((is_binary, lines, obj))
}

fn find_commit_with_context<'a>(&'a self, id: ObjectId, from_commit: Option<&str>) -> Result<gix::Commit<'a>> {
self.repo.find_commit(id).map_err(|e| {
if let Some(from) = from_commit {
GmapError::Other(format!("Object find error: {} (referenced from commit {})", e, from))
} else {
GmapError::from(e)
}
})
}

fn is_binary_object(&self, object: &gix::Object) -> bool {
object.data.as_slice().iter().take(8192).any(|&b| b == 0)
}
Expand Down Expand Up @@ -438,11 +456,12 @@ impl GitRepo {
binary: bool,
) -> Result<CommitStats> {
let commit = self.repo.find_commit(commit_id)?;

let parent_id: Option<ObjectId> = commit.parent_ids().next().map(|id| id.into());

let commit_tree = commit.tree()?;
let parent_tree = if let Some(pid) = parent_id {
Some(self.repo.find_commit(pid)?.tree()?)
Some(self.find_commit_with_context(pid, Some(&commit.id.to_string()))?.tree()?)
} else {
None
};
Expand All @@ -452,7 +471,7 @@ impl GitRepo {
.diff_tree_to_tree(parent_tree.as_ref(), Some(&commit_tree), None)?;
let mut files = Vec::new();
for change in changes {
self.handle_change(change, binary, &mut files)?;
self.handle_change(change, binary, &mut files, &commit.id.to_string())?;
}

Ok(CommitStats {
Expand Down