Skip to main content

grm/repo/worktree/
error.rs

1use std::fmt;
2
3use super::{BranchName, RemoteName, RepoChanges, WorktreeName, config, path, repo};
4
5use camino::Utf8PathBuf as PathBuf;
6use thiserror::Error;
7
8#[derive(Debug, Error)]
9pub enum Error {
10    #[error(transparent)]
11    Libgit(#[from] git2::Error),
12    #[error(transparent)]
13    Repo(#[from] repo::Error),
14    #[error(transparent)]
15    Config(#[from] config::Error),
16    #[error(transparent)]
17    InvalidWorktreeName(#[from] WorktreeValidationError),
18    #[error("Remote \"{name}\" not found")]
19    RemoteNotFound { name: RemoteName },
20    #[error("Cannot push to non-pushable remote \"{name}\"")]
21    RemoteNotPushable { name: RemoteName },
22    #[error(transparent)]
23    Io(#[from] std::io::Error),
24    #[error("Current directory does not contain a worktree setup")]
25    NotAWorktreeSetup,
26    #[error("Worktree {name} already exists")]
27    WorktreeAlreadyExists { name: WorktreeName },
28    #[error("Branch \"{0}\" not found")]
29    BranchNotFound(BranchName),
30    #[error("Worktree name is not valid utf-8")]
31    WorktreeNameNotUtf8,
32    #[error("Worktree name is empty")]
33    WorktreeNameEmpty,
34    #[error(transparent)]
35    Path(#[from] path::Error),
36    #[error("Could not determine base directory from \"{git_dir}\"")]
37    InvalidBaseDirectory { git_dir: PathBuf },
38}
39
40#[derive(Debug, Error)]
41#[error("invalid worktree name \"{name}\": {reason}")]
42pub struct WorktreeValidationError {
43    pub(super) name: String,
44    pub(super) reason: WorktreeValidationErrorReason,
45}
46
47#[derive(Debug)]
48pub enum WorktreeValidationErrorReason {
49    SlashAtStartOrEnd,
50    ConsecutiveSlashes,
51    ContainsWhitespace,
52}
53
54impl fmt::Display for WorktreeValidationErrorReason {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        write!(
57            f,
58            "{}",
59            match *self {
60                Self::SlashAtStartOrEnd => "Cannot start or end with a slash",
61                Self::ConsecutiveSlashes => "Cannot contain two consecutive slashes",
62                Self::ContainsWhitespace => "Cannot contain whitespace",
63            }
64        )
65    }
66}
67
68#[derive(Debug, Error)]
69pub enum WorktreeRemoveError {
70    #[error(transparent)]
71    RepoError(repo::Error),
72    #[error("Worktree at {0} does not exist")]
73    DoesNotExist(PathBuf),
74    #[error(
75        "Branch \"{branch_name}\" is checked out in worktree \"{worktree_name}\", this does not look correct"
76    )]
77    BranchNameMismatch {
78        worktree_name: WorktreeName,
79        branch_name: BranchName,
80    },
81    #[error("Branch {0} not found")]
82    BranchNotFound(BranchName),
83    #[error("Changes found in worktree: {0}")]
84    Changes(RepoChanges),
85    #[error("Branch {branch_name} is not merged into any persistent branches")]
86    NotMerged { branch_name: BranchName },
87    #[error("Branch {branch_name} is not in line with remote branch")]
88    NotInSyncWithRemote { branch_name: BranchName },
89    #[error("Removing {path} failed: {error}")]
90    RemoveError {
91        path: PathBuf,
92        error: std::io::Error,
93    },
94    #[error("Error getting directory entry {path}: {error}")]
95    ReadDirectoryError {
96        path: PathBuf,
97        error: std::io::Error,
98    },
99}
100
101impl From<repo::Error> for WorktreeRemoveError {
102    fn from(value: repo::Error) -> Self {
103        Self::RepoError(value)
104    }
105}
106
107#[derive(Debug, Error)]
108pub enum WorktreeConversionError {
109    #[error(transparent)]
110    RepoError(repo::Error),
111    #[error("Changes found in worktree: {0}")]
112    Changes(RepoChanges),
113    #[error("Ignored files found")]
114    Ignored,
115    #[error("{}", .0)]
116    RenameError(String),
117    #[error(transparent)]
118    Path(#[from] path::Error),
119    #[error("Opening directory failed: {0}")]
120    OpenDirectoryError(std::io::Error),
121    #[error("Removing {path} failed: {error}")]
122    RemoveError {
123        path: PathBuf,
124        error: std::io::Error,
125    },
126    #[error("Error getting directory entry: {0}")]
127    ReadDirectoryError(std::io::Error),
128}
129
130impl From<repo::Error> for WorktreeConversionError {
131    fn from(value: repo::Error) -> Self {
132        Self::RepoError(value)
133    }
134}
135
136#[derive(Debug, Error)]
137pub enum CleanupWorktreeError {
138    #[error(transparent)]
139    RepoError(#[from] Error),
140    #[error(transparent)]
141    RemoveError(#[from] WorktreeRemoveError),
142    #[error("Could not get default branch: {0}")]
143    DefaultBranch(repo::Error),
144    #[error("Branch name error: {0}")]
145    BranchName(repo::Error),
146    #[error("Branch \"{branch_name}\" not found")]
147    BranchNotFound { branch_name: BranchName },
148}
149
150pub struct CleanupWorktreeWarning {
151    pub worktree_name: WorktreeName,
152    pub reason: CleanupWorktreeWarningReason,
153}
154
155pub enum CleanupWorktreeWarningReason {
156    UncommittedChanges(RepoChanges),
157    NotMerged { branch_name: BranchName },
158    NoDirectory,
159}