From 46cee052d6d4b60b483ab6841af976d68d954705 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Sat, 26 Nov 2022 16:43:14 -0600 Subject: feat: add project filtering --- src/project/git.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/project/git.rs (limited to 'src/project/git.rs') diff --git a/src/project/git.rs b/src/project/git.rs new file mode 100644 index 0000000..f1c4d5a --- /dev/null +++ b/src/project/git.rs @@ -0,0 +1,90 @@ +use crate::{Error, Project}; +use git2::{BranchType, Repository}; +use ignore::DirEntry; +use std::{cmp::Ordering, path::PathBuf, time::Duration}; + +#[derive(Debug, Clone)] +pub struct GitProject { + path_buf: PathBuf, + latest_commit: Option, +} + +impl GitProject { + fn new(path_buf: PathBuf) -> Result { + let repository = Repository::open(&path_buf)?; + let latest_commit = Self::latest_commit(&repository); + Ok(Self { + path_buf, + latest_commit, + }) + } + + fn latest_commit(repository: &Repository) -> Option { + let mut branches = repository.branches(Some(BranchType::Local)).ok()?; + branches + .try_fold(0, |latest, branch| { + let branch = branch?.0; + + let name = branch + .name()? + .ok_or_else(|| git2::Error::from_str("Failed to find branch"))?; + + repository + .revparse_single(name)? + .peel_to_commit() + .map(|c| (c.time().seconds() as u64).max(latest)) + }) + .map(Duration::from_secs) + .ok() + } +} + +impl Project for GitProject { + fn timestamp(&self) -> Option { + self.latest_commit + } + + fn to_path_buf(&self) -> PathBuf { + self.path_buf.to_owned() + } +} + +impl PartialEq for GitProject { + fn eq(&self, other: &Self) -> bool { + match (self.latest_commit, other.latest_commit) { + (Some(time), Some(other_time)) => time.eq(&other_time), + _ => false, + } + } +} + +impl PartialOrd for GitProject { + fn partial_cmp(&self, other: &Self) -> Option { + match (self.latest_commit, other.latest_commit) { + (Some(time), Some(other_time)) => time.partial_cmp(&other_time), + _ => None, + } + } +} + +impl TryFrom for GitProject { + type Error = Error; + + fn try_from(value: PathBuf) -> Result { + Self::new(value) + } +} + +impl TryFrom for GitProject { + type Error = Error; + + fn try_from(value: DirEntry) -> Result { + Self::new(value.into_path()) + } +} + +impl From for PathBuf { + fn from(value: GitProject) -> Self { + value.path_buf + } +} -- cgit v1.2.3-70-g09d2