git_semantic/git/
parser.rs1use git2::Repository;
2use std::path::Path;
3use tracing::debug;
4
5use super::diff::DiffExtractor;
6use super::{CommitInfo, GitError};
7
8pub struct RepositoryParser {
9 repo: Repository,
10}
11
12impl RepositoryParser {
13 pub fn new(path: &Path) -> Result<Self, GitError> {
14 let repo = Repository::discover(path).map_err(GitError::RepositoryNotFound)?;
15
16 Ok(Self { repo })
17 }
18
19 pub fn parse_commits(&self, include_diffs: bool) -> Result<Vec<CommitInfo>, GitError> {
20 let mut revwalk = self.repo.revwalk()?;
21 revwalk.push_head()?;
22 revwalk.set_sorting(git2::Sort::TOPOLOGICAL | git2::Sort::TIME)?;
23
24 let mut commits = Vec::new();
25
26 for oid in revwalk {
27 let oid = oid?;
28 let commit = self.repo.find_commit(oid)?;
29
30 let hash = oid.to_string();
31 let author = commit.author().name().unwrap_or("Unknown").to_string();
32 let date =
33 chrono::DateTime::from_timestamp(commit.time().seconds(), 0).unwrap_or_default();
34 let message = commit.message().unwrap_or("").to_string();
35
36 let diff_summary = if include_diffs {
37 DiffExtractor::extract_diff(&self.repo, &commit)?
38 } else {
39 String::new()
40 };
41
42 debug!("Parsed commit: {} by {} at {}", &hash[..7], author, date);
43
44 commits.push(CommitInfo {
45 hash,
46 author,
47 date,
48 message,
49 diff_summary,
50 });
51 }
52
53 Ok(commits)
54 }
55
56 pub fn parse_commits_since(
57 &self,
58 since_hash: &str,
59 include_diffs: bool,
60 ) -> Result<Vec<CommitInfo>, GitError> {
61 let mut revwalk = self.repo.revwalk()?;
62 revwalk.push_head()?;
63 revwalk.set_sorting(git2::Sort::TOPOLOGICAL | git2::Sort::TIME)?;
64
65 let since_oid = git2::Oid::from_str(since_hash)?;
66 let mut commits = Vec::new();
67 let mut found_since = false;
68
69 for oid in revwalk {
70 let oid = oid?;
71
72 if oid == since_oid {
73 found_since = true;
74 break;
75 }
76
77 let commit = self.repo.find_commit(oid)?;
78
79 let hash = oid.to_string();
80 let author = commit.author().name().unwrap_or("Unknown").to_string();
81 let date =
82 chrono::DateTime::from_timestamp(commit.time().seconds(), 0).unwrap_or_default();
83 let message = commit.message().unwrap_or("").to_string();
84
85 let diff_summary = if include_diffs {
86 DiffExtractor::extract_diff(&self.repo, &commit)?
87 } else {
88 String::new()
89 };
90
91 commits.push(CommitInfo {
92 hash,
93 author,
94 date,
95 message,
96 diff_summary,
97 });
98 }
99
100 if !found_since {
101 return Err(GitError::CommitNotFound(since_hash.to_string()));
102 }
103
104 Ok(commits)
105 }
106}