1use std::fmt;
2
3use thiserror::Error;
4
5use crate::channel::ChannelError;
6use crate::path::{PathError, RepoPath};
7use crate::remote::RemoteError;
8
9#[derive(Debug, Error)]
10pub enum AppError {
11 #[error("git operation failed while {operation}: {details}")]
12 Git {
13 operation: &'static str,
14 details: String,
15 },
16 #[error("repository has no worktree")]
17 MissingWorktree,
18 #[error("path is not valid UTF-8: {0}")]
19 NonUtf8Path(String),
20 #[error("path escapes the repository root: {0}")]
21 PathOutsideRepo(String),
22 #[error("empty paths are not valid tracked files")]
23 EmptyPath,
24 #[error("path is not tracked at HEAD: {0}")]
25 PathNotTracked(RepoPath),
26 #[error("path is a submodule/gitlink and is out of scope: {0}")]
27 PathIsSubmodule(RepoPath),
28 #[error("failed to read .vetignore: {0}")]
29 Vetignore(String),
30 #[error("missing git config user.name")]
31 MissingUserName,
32 #[error("missing git config user.email")]
33 MissingUserEmail,
34 #[error("git config {key} is not valid UTF-8: {details}")]
35 NonUtf8GitConfig { key: &'static str, details: String },
36 #[error(
37 "target paths have uncommitted working-tree changes; rerun with --allow-dirty to proceed with committed HEAD contents"
38 )]
39 DirtyPathsRequireAllowDirty,
40 #[error("aborted because target paths have uncommitted working-tree changes")]
41 DirtyPathsDeclined,
42 #[error("invalid review channel {channel:?}: {details}")]
43 InvalidChannel { channel: String, details: String },
44 #[error("sync remote error: {0}")]
45 Remote(#[from] RemoteError),
46 #[error("I/O error: {0}")]
47 Io(#[from] std::io::Error),
48 #[error("JSON error: {0}")]
49 Json(#[from] serde_json::Error),
50}
51
52impl From<PathError> for AppError {
53 fn from(error: PathError) -> Self {
54 match error {
55 PathError::NonUtf8Path(path) => Self::NonUtf8Path(path),
56 PathError::PathOutsideRepo(path) => Self::PathOutsideRepo(path),
57 PathError::EmptyPath => Self::EmptyPath,
58 }
59 }
60}
61
62impl From<ChannelError> for AppError {
63 fn from(error: ChannelError) -> Self {
64 Self::InvalidChannel {
65 channel: error.channel,
66 details: error.details,
67 }
68 }
69}
70
71pub fn git_error(operation: &'static str, source: impl fmt::Display) -> AppError {
72 AppError::Git {
73 operation,
74 details: source.to_string(),
75 }
76}