From e554e7033320456762a82b8276e0137592d57dcb Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Fri, 5 May 2023 18:42:37 -0500 Subject: refactor: rewrite project layout --- src/project.rs | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 133 insertions(+), 13 deletions(-) (limited to 'src/project.rs') diff --git a/src/project.rs b/src/project.rs index b71a3b8..7351ae4 100644 --- a/src/project.rs +++ b/src/project.rs @@ -1,30 +1,149 @@ use std::{ - convert::Infallible, + collections::{hash_map::Entry, HashMap}, + fmt::Display, + io::{BufWriter, Write}, + ops::{Deref, DerefMut}, path::PathBuf, time::{Duration, SystemTime}, }; -pub trait Generator { - type Error: std::error::Error; +use tracing::trace; - fn generate(self) -> Result, Self::Error>; +use crate::{parser::FilterMap, path::PathMatcher}; + +#[derive(Default)] +pub struct Projects { + inner: HashMap, + filters: Vec>, +} + +impl Projects { + pub fn new() -> Self { + Self::default() + } + + pub fn add_filter(&mut self, filter: T) { + self.filters.push(Box::new(filter)) + } + + pub fn insert(&mut self, item: Project) { + let span = tracing::trace_span!("Entry", ?item); + let _guard = span.enter(); + + match self.inner.entry(item.path_buf) { + Entry::Occupied(mut occupied) if &item.timestamp > occupied.get() => { + trace!(?occupied, new_value=?item.timestamp, "New entry is more recent, replacing"); + occupied.insert(item.timestamp); + } + Entry::Occupied(occupied) => { + trace!(?occupied, new_value=?item.timestamp, "Previous entry is more recent, skipping"); + } + Entry::Vacant(v) => { + trace!(?item.timestamp, "No previous entry exists, inserting"); + v.insert(item.timestamp); + } + } + } + + pub fn write(&self, writer: W) -> Result<(), std::io::Error> { + let mut writer = BufWriter::new(writer); + let mut projects: Vec = self.inner.iter().map(Project::from).collect(); + + projects.sort(); + + projects + .into_iter() + .try_for_each(|project| writeln!(writer, "{project}")) + } +} + +impl Deref for Projects { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Projects { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } } -impl Generator for T -where - T: IntoIterator, -{ - type Error = Infallible; +impl Extend for Projects { + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + for path_buf in iter { + if let Some(project) = self.filters.filter_map(path_buf) { + self.insert(project) + } + } + } +} + +impl Extend for Projects { + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + for project in iter.into_iter() { + self.insert(project) + } + } +} - fn generate(self) -> Result, Self::Error> { - Ok(self.into_iter().collect()) +impl From for Projects { + fn from(value: crate::config::Projects) -> Self { + let mut projects = Projects::new(); + + if value.all { + projects.add_filter(PathMatcher::All); + } + + if let Some(pattern) = &value.pattern { + projects.add_filter(PathMatcher::Pattern(pattern.to_owned())); + } + + #[cfg(feature = "git")] + if value.git { + projects.add_filter(crate::git::Git); + } + + projects } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Project { pub timestamp: Duration, - pub worktree: PathBuf, + pub path_buf: PathBuf, +} + +impl Display for Project { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.path_buf.to_string_lossy()) + } +} + +impl From<(PathBuf, Duration)> for Project { + fn from((path_buf, timestamp): (PathBuf, Duration)) -> Self { + Self { + timestamp, + path_buf, + } + } +} + +impl From<(&PathBuf, &Duration)> for Project { + fn from((path_buf, timestamp): (&PathBuf, &Duration)) -> Self { + Self { + timestamp: *timestamp, + path_buf: path_buf.to_owned(), + } + } } impl TryFrom for Project { @@ -36,8 +155,9 @@ impl TryFrom for Project { .modified()? .duration_since(SystemTime::UNIX_EPOCH) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?; + Ok(Self { - worktree: value, + path_buf: value, timestamp, }) } -- cgit v1.2.3-70-g09d2