aboutsummaryrefslogtreecommitdiffstats
path: root/src/project.rs
diff options
context:
space:
mode:
authorToby Vincent <tobyv13@gmail.com>2023-05-05 18:42:37 -0500
committerToby Vincent <tobyv13@gmail.com>2023-05-05 18:42:37 -0500
commite554e7033320456762a82b8276e0137592d57dcb (patch)
tree485ce88171b3aa890806973b0eb0227b889effc5 /src/project.rs
parent5da4fb25f9bb72771c7f2798daa6339be0bc3900 (diff)
refactor: rewrite project layout
Diffstat (limited to 'src/project.rs')
-rw-r--r--src/project.rs146
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,
})
}