1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum SyncError {
5 #[error("Not a git repository: {path}")]
6 NotARepository { path: String },
7
8 #[error("Repository in unsafe state: {state}")]
9 UnsafeRepositoryState { state: String },
10
11 #[error("Not on a branch (detached HEAD)")]
12 DetachedHead,
13
14 #[error("No remote configured for branch {branch}")]
15 NoRemoteConfigured { branch: String },
16
17 #[error("Remote branch not found: {remote}/{branch}")]
18 RemoteBranchNotFound { remote: String, branch: String },
19
20 #[error("Branch {branch} not configured for sync")]
21 BranchNotConfigured { branch: String },
22
23 #[error("Manual intervention required: {reason}")]
24 ManualInterventionRequired { reason: String },
25
26 #[error("Network error: {0}")]
27 NetworkError(String),
28
29 #[error("Authentication failed during {operation}")]
30 AuthenticationFailed { operation: String },
31
32 #[error("Git command failed: {command}\n{stderr}")]
33 GitCommandFailed { command: String, stderr: String },
34
35 #[error("Git hooks rejected commit: {details}")]
36 HookRejected { details: String },
37
38 #[error("Git error: {0}")]
39 GitError(#[from] git2::Error),
40
41 #[error("IO error: {0}")]
42 IoError(#[from] std::io::Error),
43
44 #[error("Watch error: {0}")]
45 WatchError(String),
46
47 #[error("Task error: {0}")]
48 TaskError(String),
49
50 #[error("Other error: {0}")]
51 Other(String),
52}
53
54impl SyncError {
55 pub fn exit_code(&self) -> i32 {
57 match self {
58 SyncError::NotARepository { .. } => 128, SyncError::UnsafeRepositoryState { .. } => 2,
60 SyncError::DetachedHead => 2,
61 SyncError::NoRemoteConfigured { .. } => 2,
62 SyncError::RemoteBranchNotFound { .. } => 2,
63 SyncError::BranchNotConfigured { .. } => 1,
64 SyncError::ManualInterventionRequired { .. } => 1,
65 SyncError::NetworkError(_) => 3,
66 SyncError::AuthenticationFailed { .. } => 3,
67 SyncError::GitCommandFailed { .. } => 2,
68 SyncError::HookRejected { .. } => 1,
69 SyncError::GitError(e) => {
70 match e.code() {
72 git2::ErrorCode::NotFound => 128,
73 git2::ErrorCode::Conflict => 1,
74 git2::ErrorCode::Locked => 2,
75 _ => 2,
76 }
77 }
78 SyncError::IoError(_) => 2,
79 SyncError::WatchError(_) => 2,
80 SyncError::TaskError(_) => 2,
81 SyncError::Other(_) => 2,
82 }
83 }
84}
85
86pub type Result<T> = std::result::Result<T, SyncError>;
87
88impl From<notify::Error> for SyncError {
89 fn from(err: notify::Error) -> Self {
90 SyncError::WatchError(err.to_string())
91 }
92}
93
94impl From<tokio::task::JoinError> for SyncError {
95 fn from(err: tokio::task::JoinError) -> Self {
96 SyncError::TaskError(err.to_string())
97 }
98}