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}