diff options
Diffstat (limited to 'src/project')
-rw-r--r-- | src/project/error.rs | 1 | ||||
-rw-r--r-- | src/project/git.rs | 101 | ||||
-rw-r--r-- | src/project/path.rs | 78 |
3 files changed, 102 insertions, 78 deletions
diff --git a/src/project/error.rs b/src/project/error.rs index ddfcb2a..2e9f4a3 100644 --- a/src/project/error.rs +++ b/src/project/error.rs @@ -3,6 +3,7 @@ pub enum Error { #[error(transparent)] IO(#[from] std::io::Error), + #[cfg(feature = "git")] #[error(transparent)] Git(#[from] git2::Error), diff --git a/src/project/git.rs b/src/project/git.rs index 876af1c..efe4ade 100644 --- a/src/project/git.rs +++ b/src/project/git.rs @@ -2,71 +2,84 @@ use git2::{BranchType, Repository}; use ignore::DirEntry; use onefetch::ui::printer::Printer; use std::io; -use std::{cmp::Ordering, path::PathBuf, time::Duration}; +use std::{path::PathBuf, time::Duration}; +use tracing::{debug, warn}; -use crate::project::Error; -use crate::project::Preview; -use crate::project::Timestamp; -use crate::Project; +use super::{Error, Preview, ProjectParser, Timestamp}; + +#[derive(Debug, Clone)] +pub struct GitMatcher; + +impl ProjectParser for GitMatcher { + #[tracing::instrument] + fn parse_project(&self, path_buf: PathBuf) -> Option<super::ProjectItem> { + match GitProject::new(path_buf) { + Ok(g) => Some(Box::new(g)), + Err(err) => { + debug!(%err, "Failed to create git project"); + None + } + } + } +} #[derive(Debug, Clone)] pub struct GitProject { path_buf: PathBuf, - latest_commit: Option<Duration>, + latest_commit: Duration, } impl GitProject { fn new(path_buf: PathBuf) -> Result<Self, Error> { let repo = Repository::open(&path_buf)?; + let latest_commit = Self::get_timestamp(&repo); Ok(Self { path_buf, - latest_commit: Self::latest_commit(&repo).ok(), + latest_commit, }) } - fn latest_commit(repository: &Repository) -> Result<Duration, Error> { - let mut branches = repository.branches(Some(BranchType::Local))?; - branches - .try_fold(0, |latest, branch| { - let (branch, _) = branch?; - - 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) - .map_err(Into::into) + fn get_timestamp(repo: &Repository) -> Duration { + match Self::latest_commit(repo) { + Ok(s) => Duration::from_secs(s), + Err(err) => { + warn!(%err, "Failed to get latest commit from repository"); + Duration::default() + } + } } -} -impl Timestamp for GitProject { - type Error = Error; + fn latest_commit(repository: &Repository) -> Result<u64, git2::Error> { + let mut branches = repository.branches(Some(BranchType::Local))?; + branches.try_fold(0, |latest, branch| { + let (branch, _) = branch?; - fn timestamp(&self) -> Result<Duration, Self::Error> { - self.latest_commit.ok_or(Error::Git(git2::Error::from_str( - "Failed to get latest commit", - ))) + 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)) + }) } } -impl Project for GitProject { - fn to_path_buf(&self) -> &PathBuf { - &self.path_buf +impl Timestamp for GitProject { + fn timestamp(&self) -> &Duration { + &self.latest_commit } } +#[cfg(feature = "preview")] impl Preview for GitProject { type Error = Error; fn preview(&self) -> Result<(), Self::Error> { - // onefetch --include-hidden --show-logo=auto let config = onefetch::cli::Config { input: self.path_buf.to_owned(), + include_hidden: true, ..Default::default() }; @@ -77,21 +90,9 @@ impl Preview for GitProject { } } -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<Ordering> { - match (self.latest_commit, other.latest_commit) { - (Some(time), Some(other_time)) => time.partial_cmp(&other_time), - _ => None, - } +impl AsRef<PathBuf> for GitProject { + fn as_ref(&self) -> &PathBuf { + &self.path_buf } } diff --git a/src/project/path.rs b/src/project/path.rs index 14ce308..03bcac6 100644 --- a/src/project/path.rs +++ b/src/project/path.rs @@ -1,12 +1,39 @@ -use ignore::DirEntry; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::time::{Duration, SystemTime}; +use tracing::debug; + +use super::{ProjectItem, ProjectParser}; + +#[derive(Debug, Clone)] +pub struct PathMatcher(pub String); + +impl ProjectParser for PathMatcher { + #[tracing::instrument] + fn parse_project(&self, path_buf: PathBuf) -> Option<ProjectItem> { + if path_buf.join(&self.0).exists() { + Some(Box::new(PathProject::new(path_buf))) + } else { + debug!("Failed to match pattern in directory"); + None + } + } +} #[derive(Debug, PartialEq, Eq, Clone, Default)] -pub struct PathProject(PathBuf); +pub struct PathProject(PathBuf, Duration); impl PathProject { - fn new(path_buf: PathBuf) -> Self { - Self(path_buf) + pub fn new(path_buf: PathBuf) -> Self { + let modified = Self::get_modified(&path_buf).unwrap_or_default(); + Self(path_buf, modified) + } + + fn get_modified(path_buf: &Path) -> Result<Duration, std::io::Error> { + path_buf + .metadata()? + .modified()? + .duration_since(SystemTime::UNIX_EPOCH) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string())) } } @@ -16,32 +43,27 @@ impl AsRef<PathBuf> for PathProject { } } -impl TryFrom<(&String, DirEntry)> for PathProject { - type Error = String; - - fn try_from((pattern, dir_entry): (&String, DirEntry)) -> Result<Self, Self::Error> { - dir_entry - .path() - .join(pattern) - .exists() - .then(|| Self::from(dir_entry.to_owned())) - .ok_or_else(|| { - format!( - "Pattern `{:?}` not found in path: `{:?}`", - pattern, dir_entry - ) - }) +impl AsRef<Duration> for PathProject { + fn as_ref(&self) -> &Duration { + &self.1 } } -impl From<DirEntry> for PathProject { - fn from(value: DirEntry) -> Self { - Self::new(value.into_path()) - } -} +#[cfg(feature = "preview")] +impl super::Preview for PathProject { + type Error = std::io::Error; + + fn preview(&self) -> Result<(), Self::Error> { + use std::io::Write; + use std::process::{Command, Stdio}; + + let output = Command::new("ls") + .arg("-l") + .arg("-a") + .arg(&self.0) + .stdout(Stdio::piped()) + .output()?; -impl From<PathProject> for PathBuf { - fn from(value: PathProject) -> Self { - value.0 + std::io::stdout().write_all(&output.stdout) } } |