//! Commit querying operations. use crate::commit::types::*; use crate::{GitDomain, GitError, GitResult}; impl GitDomain { pub fn commit_get(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(CommitMeta::from_git2(&commit)) } pub fn commit_get_prefix(&self, prefix: &str) -> GitResult { let commit = self .repo() .find_commit_by_prefix(prefix) .map_err(|_e| GitError::InvalidOid(format!("prefix: {}", prefix)))?; Ok(CommitMeta::from_git2(&commit)) } pub fn commit_exists(&self, oid: &CommitOid) -> bool { match oid.to_oid() { Ok(oid) => self.repo.find_commit(oid).is_ok(), Err(_) => false, } } pub fn commit_is_commit(&self, oid: &CommitOid) -> bool { match oid.to_oid() { Ok(oid) => match self.repo.find_object(oid, None) { Ok(obj) => obj.kind() == Some(git2::ObjectType::Commit), Err(_) => false, }, Err(_) => false, } } pub fn commit_message(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.message().unwrap_or("").to_string()) } pub fn commit_summary(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.summary().unwrap_or("").to_string()) } pub fn commit_short_id(&self, oid: &CommitOid) -> GitResult { let _ = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; let len = oid.0.len(); if len < 7 { return Err(GitError::InvalidOid(oid.to_string())); } Ok(oid.0[..7].to_string()) } pub fn commit_author(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(CommitSignature::from_git2(commit.author())) } pub fn commit_committer(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(CommitSignature::from_git2(commit.committer())) } pub fn commit_time(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.time().seconds()) } pub fn commit_time_offset(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.time().offset_minutes()) } pub fn commit_encoding(&self, oid: &CommitOid) -> GitResult> { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.message_encoding().map(String::from)) } pub fn commit_tree_id(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(CommitOid::from_git2(commit.tree_id())) } pub fn commit_parent_count(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.parent_count()) } pub fn commit_parent_ids(&self, oid: &CommitOid) -> GitResult> { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.parent_ids().map(CommitOid::from_git2).collect()) } pub fn commit_parent(&self, oid: &CommitOid, index: usize) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; let parent = commit .parent(index) .map_err(|e| GitError::Internal(e.to_string()))?; Ok(CommitMeta::from_git2(&parent)) } pub fn commit_first_parent(&self, oid: &CommitOid) -> GitResult> { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; if commit.parent_count() > 0 { let parent = commit .parent(0) .map_err(|e| GitError::Internal(e.to_string()))?; Ok(Some(CommitMeta::from_git2(&parent))) } else { Ok(None) } } pub fn commit_is_merge(&self, oid: &CommitOid) -> GitResult { let commit = self .repo() .find_commit(oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(oid.to_string()))?; Ok(commit.parent_count() > 1) } pub fn commit_log( &self, rev: Option<&str>, offset: usize, limit: usize, ) -> GitResult> { let mut revwalk = self .repo() .revwalk() .map_err(|e| GitError::Internal(e.to_string()))?; if let Some(r) = rev { if r.contains("..") { revwalk .push_range(r) .map_err(|e| GitError::Internal(e.to_string()))?; } else { revwalk .push_ref(r) .map_err(|e| GitError::Internal(e.to_string()))?; } } else { revwalk .push_head() .map_err(|e| GitError::Internal(e.to_string()))?; } revwalk .set_sorting(git2::Sort::TOPOLOGICAL | git2::Sort::TIME) .map_err(|e| GitError::Internal(e.to_string()))?; let mut commits = Vec::new(); let target = offset.saturating_add(limit); for oid_result in revwalk { let oid = oid_result.map_err(|e| GitError::Internal(e.to_string()))?; if target > 0 && commits.len() >= target { break; } if let Ok(commit) = self.repo.find_commit(oid) { commits.push(CommitMeta::from_git2(&commit)); } } Ok(commits.into_iter().skip(offset).take(limit).collect()) } pub fn commit_range(&self, from: &str, to: &str) -> GitResult> { let range = format!("{}..{}", from, to); self.commit_log(Some(&range), 0, 0) } pub fn commit_count(&self, from: Option<&str>, to: Option<&str>) -> GitResult { let rev = match (from, to) { (Some(f), Some(t)) => Some(format!("{}..{}", f, t)), (Some(f), None) => Some(f.to_string()), (None, Some(t)) => Some(t.to_string()), (None, None) => None, }; let commits = self.commit_log(rev.as_deref(), 0, 0)?; Ok(commits.len()) } pub fn commit_total(&self, rev: Option<&str>) -> GitResult { self.commit_count(None, rev) } }