use git2::{BranchType, Error, Repository}; use std::{path::PathBuf, time::Duration}; use crate::{parser::Parser, project::Project}; #[derive(Debug, Clone)] pub struct Git; impl Parser for Git { type Error = Error; #[tracing::instrument] fn parse(&self, path_buf: PathBuf) -> Result { Repository::open(&path_buf)?.parse(path_buf) } } impl Parser for Repository { type Error = Error; fn parse(&self, path_buf: PathBuf) -> Result { let opt_commit = self .branches(Some(BranchType::Local))? .map(|branch| -> Result<_, Error> { let (branch, _) = branch?; let name = branch .name()? .ok_or_else(|| Error::from_str("Failed to get branch name"))?; self.revparse_single(name)?.peel_to_commit() }) .inspect(|res| { if let Err(err) = res { tracing::warn!(%err, "Skipping errored branch") } }) .flatten() .max_by_key(|c| c.time().seconds() as u64); let timestamp = match opt_commit { Some(c) => { let time = c.time().seconds(); let id = c.id(); tracing::debug!(?path_buf, ?id, ?time, "Latest commit"); Duration::from_secs(c.time().seconds() as u64) } None => { tracing::warn!(?path_buf, "No commit found, using default"); Duration::default() } }; Ok(Project { path_buf, timestamp, }) } }