git_sync_rs/
error.rs

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("Branch {branch} not configured for sync")]
18    BranchNotConfigured { branch: String },
19
20    #[error("Manual intervention required: {reason}")]
21    ManualInterventionRequired { reason: String },
22
23    #[error("Network error: {0}")]
24    NetworkError(String),
25
26    #[error("Git error: {0}")]
27    GitError(#[from] git2::Error),
28
29    #[error("IO error: {0}")]
30    IoError(#[from] std::io::Error),
31
32    #[error("Watch error: {0}")]
33    WatchError(String),
34
35    #[error("Task error: {0}")]
36    TaskError(String),
37
38    #[error("Other error: {0}")]
39    Other(String),
40}
41
42impl SyncError {
43    /// Get the exit code for this error type, matching the original git-sync
44    pub fn exit_code(&self) -> i32 {
45        match self {
46            SyncError::NotARepository { .. } => 128, // Match git's error code
47            SyncError::UnsafeRepositoryState { .. } => 2,
48            SyncError::DetachedHead => 2,
49            SyncError::NoRemoteConfigured { .. } => 2,
50            SyncError::BranchNotConfigured { .. } => 1,
51            SyncError::ManualInterventionRequired { .. } => 1,
52            SyncError::NetworkError(_) => 3,
53            SyncError::GitError(e) => {
54                // Map git2 errors to appropriate exit codes
55                match e.code() {
56                    git2::ErrorCode::NotFound => 128,
57                    git2::ErrorCode::Conflict => 1,
58                    git2::ErrorCode::Locked => 2,
59                    _ => 2,
60                }
61            }
62            SyncError::IoError(_) => 2,
63            SyncError::WatchError(_) => 2,
64            SyncError::TaskError(_) => 2,
65            SyncError::Other(_) => 2,
66        }
67    }
68}
69
70pub type Result<T> = std::result::Result<T, SyncError>;
71
72impl From<notify::Error> for SyncError {
73    fn from(err: notify::Error) -> Self {
74        SyncError::WatchError(err.to_string())
75    }
76}
77
78impl From<tokio::task::JoinError> for SyncError {
79    fn from(err: tokio::task::JoinError) -> Self {
80        SyncError::TaskError(err.to_string())
81    }
82}