irox_git_tools/
error.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2023 IROX Contributors
3//
4
5use 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 {}