diff options
author | Toby Vincent <tobyv13@gmail.com> | 2023-05-05 18:42:37 -0500 |
---|---|---|
committer | Toby Vincent <tobyv13@gmail.com> | 2023-05-05 18:42:37 -0500 |
commit | e554e7033320456762a82b8276e0137592d57dcb (patch) | |
tree | 485ce88171b3aa890806973b0eb0227b889effc5 /src/project.rs | |
parent | 5da4fb25f9bb72771c7f2798daa6339be0bc3900 (diff) |
refactor: rewrite project layout
Diffstat (limited to 'src/project.rs')
-rw-r--r-- | src/project.rs | 146 |
1 files changed, 133 insertions, 13 deletions
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<Vec<Project>, Self::Error>; +use crate::{parser::FilterMap, path::PathMatcher}; + +#[derive(Default)] +pub struct Projects { + inner: HashMap<PathBuf, Duration>, + filters: Vec<Box<dyn FilterMap>>, +} + +impl Projects { + pub fn new() -> Self { + Self::default() + } + + pub fn add_filter<T: FilterMap + 'static>(&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<W: Write>(&self, writer: W) -> Result<(), std::io::Error> { + let mut writer = BufWriter::new(writer); + let mut projects: Vec<Project> = 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<PathBuf, Duration>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Projects { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } } -impl<T> Generator for T -where - T: IntoIterator<Item = Project>, -{ - type Error = Infallible; +impl Extend<PathBuf> for Projects { + fn extend<T>(&mut self, iter: T) + where + T: IntoIterator<Item = PathBuf>, + { + for path_buf in iter { + if let Some(project) = self.filters.filter_map(path_buf) { + self.insert(project) + } + } + } +} + +impl Extend<Project> for Projects { + fn extend<T>(&mut self, iter: T) + where + T: IntoIterator<Item = Project>, + { + for project in iter.into_iter() { + self.insert(project) + } + } +} - fn generate(self) -> Result<Vec<Project>, Self::Error> { - Ok(self.into_iter().collect()) +impl From<crate::config::Projects> 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<PathBuf> for Project { @@ -36,8 +155,9 @@ impl TryFrom<PathBuf> 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, }) } |