grit_lib/refs/store/
error.rs1use std::fmt;
4use std::sync::Arc;
5
6use crate::git_dir::GitDirPathOperation;
7use crate::objects::{ObjectId, ObjectKind};
8use crate::refs::RefnameUnavailable;
9
10use super::{Expected, RawRef};
11
12#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
14#[non_exhaustive]
15pub enum RefStoreError {
16 #[error("reflog '{name}' changed during rewrite")]
19 ReflogRewriteStale {
20 name: String,
22 },
23
24 #[error("cannot lock ref '{name}': lock held")]
31 LockHeld {
32 name: String,
35 },
36
37 #[error("ref '{name}' did not match expected state")]
39 ExpectedMismatch {
40 name: String,
42 expected: Expected,
44 actual: Option<RawRef>,
46 },
47
48 #[error("cannot lock ref '{}': {}", reason.refname(), reason.lock_message_suffix())]
50 NameUnavailable {
51 reason: RefnameUnavailable,
53 },
54
55 #[error("multiple updates for ref '{name}' not allowed")]
57 DuplicateUpdate {
58 name: String,
60 },
61
62 #[error("symbolic ref loop or chain too deep")]
64 SymrefLoop,
65
66 #[error("ref not found: {name}")]
68 NotFound {
69 name: String,
71 },
72
73 #[error("corrupt ref store: {0}")]
75 Corrupt(String),
76
77 #[error("{}", crate::git_dir::io_error::format_git_dir_io_message(.path, *operation, &Self::git_dir_io_source(*.os_error)))]
79 GitDirPathIo {
80 path: String,
82 operation: GitDirPathOperation,
84 os_error: i32,
86 },
87
88 #[error("refusing to update ref with bad name '{name}'")]
93 InvalidRefName {
94 name: String,
96 },
97
98 #[error("refusing to point '{name}' at symbolic target '{target}'")]
101 InvalidSymrefTarget {
102 name: String,
104 target: String,
106 },
107
108 #[error("refusing to point ref '{name}' at the null object id")]
114 NullOid {
115 name: String,
117 },
118
119 #[error("refusing to point ref '{name}' at {oid}: no such object in the repository")]
125 MissingObject {
126 name: String,
128 oid: ObjectId,
130 },
131
132 #[error("refusing to point '{name}' at {kind} {oid}: branches and HEAD must name a commit")]
138 NotACommit {
139 name: String,
141 oid: ObjectId,
143 kind: ObjectKind,
145 },
146
147 #[error("cannot check object {oid} for ref '{name}': {source}")]
150 ObjectLookup {
151 name: String,
153 oid: ObjectId,
155 source: BackendError,
157 },
158
159 #[error(transparent)]
161 InvalidReflog(#[from] crate::ident::SignatureError),
162
163 #[error(transparent)]
167 Backend(BackendError),
168
169 #[error(transparent)]
171 Hook(ReferenceTransactionHookErr),
172}
173
174#[derive(Clone, Debug)]
176pub struct ReferenceTransactionHookErr(Arc<crate::hooks::HookError>);
177
178impl PartialEq for ReferenceTransactionHookErr {
179 fn eq(&self, other: &Self) -> bool {
180 self.0.to_string() == other.0.to_string()
181 }
182}
183
184impl Eq for ReferenceTransactionHookErr {}
185
186impl From<crate::hooks::HookError> for ReferenceTransactionHookErr {
187 fn from(value: crate::hooks::HookError) -> Self {
188 Self(Arc::new(value))
189 }
190}
191
192impl ReferenceTransactionHookErr {
193 pub(crate) fn into_hook_error(self) -> crate::hooks::HookError {
194 Arc::try_unwrap(self.0).unwrap_or_else(|arc| match arc.as_ref() {
195 crate::hooks::HookError::Failed {
196 hook_name,
197 status,
198 output,
199 } => crate::hooks::HookError::Failed {
200 hook_name: hook_name.clone(),
201 status: *status,
202 output: output.clone(),
203 },
204 crate::hooks::HookError::Spawn {
205 hook_name,
206 path,
207 source,
208 output,
209 } => crate::hooks::HookError::Spawn {
210 hook_name: hook_name.clone(),
211 path: path.clone(),
212 source: std::io::Error::new(source.kind(), source.to_string()),
213 output: output.clone(),
214 },
215 crate::hooks::HookError::Internal(msg) => {
216 crate::hooks::HookError::Internal(msg.clone())
217 }
218 })
219 }
220}
221
222impl std::fmt::Display for ReferenceTransactionHookErr {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 self.0.fmt(f)
225 }
226}
227
228impl std::error::Error for ReferenceTransactionHookErr {
229 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
230 Some(self.0.as_ref())
231 }
232}
233
234impl RefStoreError {
235 pub(crate) fn git_dir_path_io(
236 path: String,
237 operation: GitDirPathOperation,
238 source: std::io::Error,
239 ) -> Self {
240 Self::GitDirPathIo {
241 path,
242 operation,
243 os_error: source.raw_os_error().unwrap_or(0),
244 }
245 }
246
247 pub(crate) fn git_dir_io_source(os_error: i32) -> std::io::Error {
248 if os_error == 0 {
249 std::io::Error::from(std::io::ErrorKind::Other)
250 } else {
251 std::io::Error::from_raw_os_error(os_error)
252 }
253 }
254
255 pub(crate) fn not_found(name: &str) -> Self {
256 Self::NotFound {
257 name: name.to_owned(),
258 }
259 }
260
261 pub fn backend(err: impl std::error::Error + Send + Sync + 'static) -> Self {
263 Self::Backend(BackendError::new(err))
264 }
265}
266
267#[derive(Clone)]
272pub struct BackendError(Arc<dyn std::error::Error + Send + Sync + 'static>);
273
274impl BackendError {
275 pub fn new(err: impl std::error::Error + Send + Sync + 'static) -> Self {
277 Self(Arc::new(err))
278 }
279
280 #[must_use]
282 pub fn get_ref(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
283 self.0.as_ref()
284 }
285
286 #[must_use]
288 pub fn downcast_ref<E: std::error::Error + 'static>(&self) -> Option<&E> {
289 self.0.downcast_ref::<E>()
290 }
291}
292
293impl fmt::Debug for BackendError {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 fmt::Debug::fmt(&self.0, f)
296 }
297}
298
299impl fmt::Display for BackendError {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 fmt::Display::fmt(&self.0, f)
302 }
303}
304
305impl std::error::Error for BackendError {
306 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
307 self.0.source()
308 }
309}
310
311impl PartialEq for BackendError {
312 fn eq(&self, other: &Self) -> bool {
313 Arc::ptr_eq(&self.0, &other.0)
314 }
315}
316
317impl Eq for BackendError {}
318
319impl From<BackendError> for RefStoreError {
320 fn from(err: BackendError) -> Self {
321 Self::Backend(err)
322 }
323}
324
325impl From<RefnameUnavailable> for RefStoreError {
326 fn from(reason: RefnameUnavailable) -> Self {
327 Self::NameUnavailable { reason }
328 }
329}