Skip to main content

atelier_sdk/
error.rs

1use std::path::PathBuf;
2
3use thiserror::Error;
4
5/// Every way a core operation can fail.
6///
7/// The domain variants are outcomes callers match on by name; the last
8/// three wrap a lower layer (the engine, the filesystem, config parsing)
9/// whose detail is carried as a message.
10#[derive(Debug, Error)]
11pub enum Error {
12    /// The path is not inside an atelier workspace.
13    #[error("not a workspace: {0}")]
14    NotAWorkspace(PathBuf),
15
16    /// `init` refused: the path already holds a workspace.
17    #[error("a workspace already exists at {0}")]
18    WorkspaceExists(PathBuf),
19
20    /// `init` refused: the path sits inside an existing workspace.
21    #[error("cannot nest a workspace inside the one at {0}")]
22    NestedWorkspace(PathBuf),
23
24    /// `attach` refused: the mount name is already taken.
25    #[error("a source is already attached to this workspace")]
26    AlreadyAttached,
27
28    /// Adoption refused: the git source uses git-lfs.
29    #[error("git-lfs sources are unsupported")]
30    LfsSourceUnsupported,
31
32    /// No config home names an actor; see `resolve_actor`.
33    #[error("no actor is configured")]
34    NoActorConfigured,
35
36    /// No session carries the given id.
37    #[error("no session {0}")]
38    SessionNotFound(String),
39
40    /// The session left the open state; the operation needs it open.
41    #[error("session {id} is {state}")]
42    SessionClosed {
43        /// The session's id.
44        id: String,
45        /// The state the session is in.
46        state: String,
47    },
48
49    /// No landing request carries the given id.
50    #[error("no landing request {0}")]
51    RequestNotFound(String),
52
53    /// The landing request left the open state; the operation needs it open.
54    #[error("landing request {id} is {state}")]
55    RequestClosed {
56        /// The request's id.
57        id: String,
58        /// The state the request is in.
59        state: String,
60    },
61
62    /// The landing request hit a conflict and parked.
63    #[error(
64        "landing request {0} is parked on a conflict; a new snapshot on its change re-opens the gate"
65    )]
66    RequestParked(String),
67
68    /// The workspace's landing policy forbids self-approval.
69    #[error("this workspace forbids approving your own landing request")]
70    SelfApprovalForbidden,
71
72    /// The change gained a snapshot after approval, so the approvals no
73    /// longer vouch for what would land.
74    #[error("approvals were dismissed: the change has a new snapshot {new_snapshot}")]
75    ApprovalsDismissed {
76        /// The snapshot that dismissed the approvals.
77        new_snapshot: String,
78    },
79
80    /// Another actor holds the landing lease.
81    #[error("the landing lease is held by {holder} until {expires_at_ms}")]
82    LeaseHeld {
83        /// The actor holding the lease.
84        holder: String,
85        /// When the lease expires, in unix milliseconds.
86        expires_at_ms: i64,
87    },
88
89    /// The path escapes the session's working copy.
90    #[error("path {0} leaves the session working copy")]
91    PathOutsideWorkingCopy(String),
92
93    /// The file has no projecting package and its bytes are not text.
94    #[error("no format package projects {0} and it is not utf-8 text")]
95    NotText(String),
96
97    /// The requested read window exceeds the maximum.
98    #[error("read windows span 1 to {max} bytes")]
99    WindowTooLarge {
100        /// The largest window a read accepts, in bytes.
101        max: usize,
102    },
103
104    /// A format package failed while handling a document it claimed.
105    #[error("package {package} failed: {reason}")]
106    PackageFailed {
107        /// The failing package's id.
108        package: String,
109        /// Why it failed, in the package's own words.
110        reason: String,
111    },
112
113    /// An engine-layer failure: jj or `SQLite`.
114    #[error("engine error: {0}")]
115    Engine(String),
116
117    /// A filesystem failure.
118    // The io source is deliberately absent from the message: callers render
119    // the error chain, where the source already appears once.
120    #[error("i/o error")]
121    Io(#[from] std::io::Error),
122
123    /// A config-layer failure: TOML or time formatting.
124    #[error("config error: {0}")]
125    Config(String),
126}
127
128/// Wrap an engine-layer failure (jj, `SQLite`) as [`Error::Engine`].
129pub(crate) fn engine_err(source: impl std::fmt::Display) -> Error {
130    Error::Engine(source.to_string())
131}
132
133/// Wrap a config-layer failure (TOML, time) as [`Error::Config`].
134pub(crate) fn config_err(source: impl std::fmt::Display) -> Error {
135    Error::Config(source.to_string())
136}