gps 7.3.3

Official CLI & library for Git Patch Stack
Documentation
use git2;
use std::result::Result;

#[derive(Debug)]
pub enum CommitDiffError {
    MergeCommit,
    CommitParentCountZero,
    GetParentZeroFailed,
    GetParentZeroCommitFailed,
    GetParentZeroTreeFailed,
    GetCommitTreeFailed,
    GetDiffTreeToTreeFailed,
}

impl std::fmt::Display for CommitDiffError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::MergeCommit => write!(f, "can't diff a merge commit"),
            Self::CommitParentCountZero => write!(f, "parent count is zero"),
            Self::GetParentZeroFailed => write!(f, "failed to get parent 0 oid"),
            Self::GetParentZeroCommitFailed => write!(f, "failed to get parent 0 commit"),
            Self::GetParentZeroTreeFailed => write!(f, "failed to get parent 0 tree"),
            Self::GetCommitTreeFailed => write!(f, "failed to get tree of given commit"),
            Self::GetDiffTreeToTreeFailed => write!(f, "failed to generate diff from trees"),
        }
    }
}

impl std::error::Error for CommitDiffError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

pub fn commit_diff<'a>(
    repo: &'a git2::Repository,
    commit: &git2::Commit,
) -> Result<git2::Diff<'a>, CommitDiffError> {
    if commit.parent_count() > 1 {
        return Err(CommitDiffError::MergeCommit);
    }

    if commit.parent_count() > 0 {
        let parent_oid = commit
            .parent_id(0)
            .map_err(|_| CommitDiffError::GetParentZeroFailed)?;
        let parent_commit = repo
            .find_commit(parent_oid)
            .map_err(|_| CommitDiffError::GetParentZeroCommitFailed)?;
        let parent_tree = parent_commit
            .tree()
            .map_err(|_| CommitDiffError::GetParentZeroTreeFailed)?;

        let commit_tree = commit
            .tree()
            .map_err(|_| CommitDiffError::GetCommitTreeFailed)?;
        Ok(repo
            .diff_tree_to_tree(Some(&parent_tree), Some(&commit_tree), Option::None)
            .map_err(|_| CommitDiffError::GetDiffTreeToTreeFailed)?)
    } else {
        Err(CommitDiffError::CommitParentCountZero)
    }
}