aboutsummaryrefslogtreecommitdiffstats
path: root/src/project
diff options
context:
space:
mode:
authorToby Vincent <tobyv13@gmail.com>2022-11-28 16:09:29 -0600
committerToby Vincent <tobyv13@gmail.com>2022-11-28 16:09:29 -0600
commitda884530e2b3e0b9a5bef9abcf683a970b93bd6b (patch)
tree84653f0fc4e643bb2d2c6d6a1eff79fdd94fbf07 /src/project
parentf7eeef26d5a251c2a925d18d288fec2fa205f59d (diff)
feat: add git and preview (default) features
Diffstat (limited to 'src/project')
-rw-r--r--src/project/error.rs1
-rw-r--r--src/project/git.rs101
-rw-r--r--src/project/path.rs78
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)
}
}