1use git2::{Commit, Oid, Reference, Repository, Tree};
6use std::fmt::{Display, Formatter};
7use std::path::Path;
8
9#[derive(Debug, Clone)]
10pub enum Error {
11 Discovery {
12 path: String,
13 },
14 Worktree {
15 path: String,
16 },
17 Head {
18 path: String,
19 },
20 ReferenceNotInRepo {
21 path: String,
22 reference: String,
23 },
24 NoTreeForCommit {
25 path: String,
26 commit: String,
27 tree: String,
28 },
29 Revwalk {
30 path: String,
31 },
32 CommandError {
33 path: String,
34 cmd: String,
35 error: String,
36 },
37 Diff {
38 path: String,
39 tree1: String,
40 tree2: String,
41 },
42 Branch {
43 path: String,
44 name: String,
45 },
46}
47
48impl Error {
49 pub fn discovery<T>(path: &Path) -> Result<T, Error> {
50 Err(Error::Discovery {
51 path: path.display().to_string(),
52 })
53 }
54 pub fn worktree<T>(path: &Path) -> Result<T, Error> {
55 Err(Error::Worktree {
56 path: path.display().to_string(),
57 })
58 }
59 pub fn head<T>(path: &Path) -> Result<T, Error> {
60 Err(Error::Head {
61 path: path.display().to_string(),
62 })
63 }
64 pub fn ref_not_in_repo(repo: &Repository, reference: &Reference) -> Self {
65 Error::ReferenceNotInRepo {
66 path: repo.path().display().to_string(),
67 reference: String::from_utf8_lossy(reference.name_bytes()).to_string(),
68 }
69 }
70 pub fn ref_not_in_repo_err<T>(repo: &Repository, reference: &Reference) -> Result<T, Error> {
71 Err(Error::ref_not_in_repo(repo, reference))
72 }
73 pub fn id_not_in_repo(repo: &Repository, id: &Oid) -> Self {
74 Error::ReferenceNotInRepo {
75 path: repo.path().display().to_string(),
76 reference: id.to_string(),
77 }
78 }
79 pub fn id_not_in_repo_err<T>(repo: &Repository, commit: &Commit) -> Result<T, Error> {
80 Err(Error::id_not_in_repo(repo, &commit.id()))
81 }
82 pub fn no_tree_for_commit(repo: &Repository, commit: &Commit) -> Self {
83 Error::NoTreeForCommit {
84 path: repo.path().display().to_string(),
85 commit: commit.id().to_string(),
86 tree: commit.tree_id().to_string(),
87 }
88 }
89 pub fn no_tree_for_commit_err<T>(repo: &Repository, commit: &Commit) -> Result<T, Error> {
90 Err(Error::no_tree_for_commit(repo, commit))
91 }
92 pub fn revwalk_err<T>(repo: &Repository) -> Result<T, Error> {
93 Err(Error::revwalk(repo))
94 }
95
96 pub fn revwalk(repo: &Repository) -> Error {
97 Error::Revwalk {
98 path: repo.path().display().to_string(),
99 }
100 }
101 pub fn command_err<T>(
102 repo: &Repository,
103 cmd: &'static str,
104 err: &git2::Error,
105 ) -> Result<T, Error> {
106 Err(Error::CommandError {
107 path: repo.path().display().to_string(),
108 cmd: cmd.to_string(),
109 error: format!("{err}"),
110 })
111 }
112 pub fn diff_tree(repo: &Repository, tree1: &Tree, tree2: &Tree) -> Self {
113 Error::Diff {
114 path: repo.path().display().to_string(),
115 tree1: tree1.id().to_string(),
116 tree2: tree2.id().to_string(),
117 }
118 }
119 pub fn diff_tree_err<T>(repo: &Repository, tree1: &Tree, tree2: &Tree) -> Result<T, Self> {
120 Err(Error::diff_tree(repo, tree1, tree2))
121 }
122 pub fn branch_err<T>(repo: &Repository, name: &str) -> Result<T, Error> {
123 Err(Error::Branch {
124 path: repo.path().display().to_string(),
125 name: name.to_string(),
126 })
127 }
128}
129
130impl Display for Error {
131 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132 match self {
133 Error::Discovery { path } => write!(f, "Unable to discover repo at {path}"),
134 Error::Worktree { path } => write!(f, "Unable to repo worktree at {path}"),
135 Error::Head { path } => write!(f, "Unable to find HEAD for repo at {path}"),
136 Error::ReferenceNotInRepo { path, reference } => write!(
137 f,
138 "Unable to find commit for HEAD:{reference} within repo at {path}"
139 ),
140 Error::NoTreeForCommit { path, commit, tree } => write!(
141 f,
142 "Unable to find tree for commit {commit} in repo {path} with id {tree}"
143 ),
144 Error::Revwalk { path } => write!(f, "Error creating/executing revwalk in {path}"),
145
146 Error::CommandError { path, cmd, error } => {
147 write!(f, "Error running command {cmd} in repo {path}: {error}")
148 }
149 Error::Diff { path, tree1, tree2 } => write!(
150 f,
151 "Error generating diff between {tree1} and {tree2} in repo {path}"
152 ),
153 Error::Branch { path, name } => {
154 write!(f, "Unable to find local branch {name} in repo {path}")
155 }
156 }
157 }
158}
159
160impl std::error::Error for Error {}