1use std::{
2 fmt::Display,
3 path::{Path, PathBuf},
4};
5
6use git2::{Repository, Status};
7
8pub enum RepositoryChangeStatus {
9 UpToDate,
10 NoRepository,
11 UncommittedChanges(usize),
12}
13
14pub enum GetRepositoryChangersError {
15 CannotOpenRepository { path: PathBuf, reason: String },
16 CannotReadStatus { path: PathBuf, reason: String },
17}
18
19pub fn get_repository_changes<T>(
20 path: T,
21) -> Result<RepositoryChangeStatus, GetRepositoryChangersError>
22where
23 T: AsRef<Path>,
24{
25 let repository = Repository::open(path.as_ref());
26 let repository = match repository {
27 Ok(repository) => repository,
28 Err(error) => match error.code() {
29 git2::ErrorCode::NotFound => todo!(),
30 _ => {
31 return Err(GetRepositoryChangersError::CannotOpenRepository {
32 path: path.as_ref().into(),
33 reason: error.message().to_string(),
34 })
35 }
36 },
37 };
38
39 let statuses = repository.statuses(None);
40 let statuses = match statuses {
41 Ok(statuses) => statuses,
42 Err(error) => {
43 return Err(GetRepositoryChangersError::CannotReadStatus {
44 path: path.as_ref().into(),
45 reason: error.message().to_string(),
46 })
47 }
48 };
49 match statuses
50 .iter()
51 .filter(|status| !matches!(status.status(), Status::IGNORED))
52 .count()
53 {
54 0 => Ok(RepositoryChangeStatus::UpToDate),
55 num_changes => Ok(RepositoryChangeStatus::UncommittedChanges(num_changes)),
56 }
57}
58
59impl Display for RepositoryChangeStatus {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 match self {
62 RepositoryChangeStatus::UpToDate => write!(f, "No changes"),
63 RepositoryChangeStatus::NoRepository => write!(f, "No repository"),
64 RepositoryChangeStatus::UncommittedChanges(n) => write!(f, "{} uncommitted changes", n),
65 }
66 }
67}