git-ents.gitmain
⌘K
foforge
error.rs187 lines · 6.4 KB · rusthistorycomment on this file
1//! The porcelain-wide error type: every subcommand's failure, rendered for
2//! a terminal.
3
4use std::path::PathBuf;
5
6/// Every way a `git-ents` subcommand can fail.
7///
8/// Each variant documents when it occurs and what the user should do —
9/// this is the only layer that renders a failure for a human, so the
10/// detail belongs here rather than in a library crate's own error type.
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13 /// The current directory is not inside a git repository, or the
14 /// discovered repository has no `.git` directory `git-ents` can open.
15 /// Run the command inside a git repository.
16 #[error("not a git repository (or any parent up to mount point): {path}")]
17 NotARepo {
18 /// The directory `git-ents` started looking from.
19 path: PathBuf,
20 },
21
22 /// No signing key could be resolved: `--key` was not given,
23 /// `user.signingkey` is unset, and no default key exists at
24 /// `~/.ssh/id_ed25519`. Run `git ents setup` first.
25 #[error("no signing key configured; run `git ents setup` or pass --key")]
26 NoSigningKey,
27
28 /// The signing key at `path` could not be read as an OpenSSH private
29 /// key, or is passphrase-protected (unsupported in this phase: use an
30 /// unencrypted key, or load one via `ssh-agent` in a future phase).
31 #[error("cannot use signing key at {path}: {detail}")]
32 BadSigningKey {
33 /// The key file that failed to load.
34 path: PathBuf,
35 /// What went wrong.
36 detail: String,
37 },
38
39 /// The gate refused the proposed mutation (`gate.verdict-reason`): the
40 /// refusal's own rendering names the rule and offers the inbox
41 /// alternative when one applies.
42 #[error("rejected: {0}")]
43 Refused(String),
44
45 /// `receive` rejected the batch as a stale compare-and-swap: another
46 /// writer moved a ref between read and write. Retry the command.
47 #[error("rejected: {name} changed concurrently, retry")]
48 Stale {
49 /// The ref whose precondition was stale.
50 name: String,
51 },
52
53 /// A previously redacted object would have been refilled by this
54 /// mutation (`receive.redaction-ingest`); the mutation is refused.
55 #[error("refused: object {oid} was redacted and cannot be refilled")]
56 Redacted {
57 /// The redacted object id.
58 oid: gix_hash::ObjectId,
59 },
60
61 /// The named entity (member, effect, toolchain, comment, inbox entry)
62 /// does not exist.
63 #[error("not found: {what}")]
64 NotFound {
65 /// What was being looked up.
66 what: String,
67 },
68
69 /// A local (non-git, non-gate) I/O failure: reading or writing a file
70 /// outside the object database.
71 #[error("io error at {path}: {source}")]
72 Io {
73 /// The path being read or written.
74 path: PathBuf,
75 /// The underlying I/O failure.
76 #[source]
77 source: std::io::Error,
78 },
79
80 /// A `git push` run on the operator's behalf failed: the remote's
81 /// gate refused the enrollment, or the transport itself failed.
82 #[error("push of {refspec} to {remote} failed:\n{stderr}")]
83 Push {
84 /// The refspec being pushed.
85 refspec: String,
86 /// The remote pushed to.
87 remote: String,
88 /// git's own stderr, which carries the gate's refusal
89 /// (`gate.verdict-reason`) when there is one.
90 stderr: String,
91 },
92
93 /// A malformed command-line argument that passed `figue`'s own parsing
94 /// but fails a semantic check this crate makes (an invalid line range,
95 /// an unparsable oid, ...).
96 #[error("invalid argument: {0}")]
97 InvalidArgument(String),
98
99 /// Opening or reading the local git repository failed. Boxed (like the
100 /// other large variants below): `gix::open::Error` is large enough on
101 /// its own to trip `clippy::result_large_err` for every fallible
102 /// function in this crate if stored inline, the same reasoning
103 /// `ents-effect`'s own error type documents for its boxed
104 /// `ents_receive::Error` variant.
105 #[error(transparent)]
106 Repo(Box<gix::open::Error>),
107
108 /// A `gix-ref-store` failure: reading or writing a ref.
109 #[error(transparent)]
110 Refs(#[from] gix_ref_store::Error),
111
112 /// An `ents-gate` failure: the gate itself could not reach a verdict
113 /// (a store or object read failed), distinct from a reached refusal.
114 #[error(transparent)]
115 Gate(#[from] ents_gate::Error),
116
117 /// An `ents-receive` failure: `receive` itself could not reach an
118 /// outcome. Boxed; see [`Error::Repo`]'s own doc.
119 #[error(transparent)]
120 Receive(Box<ents_receive::Error>),
121
122 /// An `ents-effect` failure: toolchain resolution, materialization, or
123 /// the executor itself. Boxed; see [`Error::Repo`]'s own doc.
124 #[error(transparent)]
125 Effect(Box<ents_effect::Error>),
126
127 /// An `ents-anchor` failure: capturing or projecting a code anchor.
128 #[error(transparent)]
129 Anchor(#[from] ents_anchor::Error),
130
131 /// An `ents-sync` failure: pre-flight, routing, or merge. Boxed; see
132 /// [`Error::Repo`]'s own doc.
133 #[error(transparent)]
134 Sync(Box<ents_sync::Error>),
135
136 /// An `ents-model` failure: building or validating a refname or typed
137 /// tree.
138 #[error(transparent)]
139 Model(#[from] ents_model::Error),
140
141 /// A `facet-git-tree` (de)serialization failure.
142 #[error(transparent)]
143 Tree(#[from] facet_git_tree::Error),
144
145 /// A raw object-store write failed (building a toolchain import's tree,
146 /// or a mutation commit).
147 #[error(transparent)]
148 ObjectWrite(#[from] gix_object::write::Error),
149
150 /// An `ents-forge` failure: anchoring, serializing, or proposing a
151 /// comment mutation. Boxed; see [`Error::Repo`]'s own doc.
152 #[error(transparent)]
153 Forge(Box<ents_forge::Error>),
154}
155
156impl From<gix::open::Error> for Error {
157 fn from(source: gix::open::Error) -> Self {
158 Self::Repo(Box::new(source))
159 }
160}
161
162impl From<ents_receive::Error> for Error {
163 fn from(source: ents_receive::Error) -> Self {
164 Self::Receive(Box::new(source))
165 }
166}
167
168impl From<ents_effect::Error> for Error {
169 fn from(source: ents_effect::Error) -> Self {
170 Self::Effect(Box::new(source))
171 }
172}
173
174impl From<ents_sync::Error> for Error {
175 fn from(source: ents_sync::Error) -> Self {
176 Self::Sync(Box::new(source))
177 }
178}
179
180impl From<ents_forge::Error> for Error {
181 fn from(source: ents_forge::Error) -> Self {
182 Self::Forge(Box::new(source))
183 }
184}
185
186/// This crate's `Result` alias.
187pub type Result<T> = std::result::Result<T, Error>;