1#![allow(missing_docs)]
2
3use thiserror::Error;
4
5#[derive(Error, Debug)]
7pub enum Error {
8 #[error("couldn't find `cargo`, which is a dependency of this cli (set 'PERSEUS_CARGO_PATH' to another location if you've installed it elsewhere)")]
9 CargoNotPresent {
10 #[source]
11 source: std::io::Error,
12 },
13 #[error(
14 "couldn't install `wasm32-unknown-unknown` target (do you have an internet connection?)"
15 )]
16 RustupTargetAddFailed { code: i32 },
17 #[error("couldn't get current directory (have you just deleted it?)")]
18 CurrentDirUnavailable {
19 #[source]
20 source: std::io::Error,
21 },
22 #[error(transparent)]
23 ExecutionError(#[from] ExecutionError),
24 #[error(transparent)]
25 ExportError(#[from] ExportError),
26 #[error(transparent)]
27 DeployError(#[from] DeployError),
28 #[error(transparent)]
29 WatchError(#[from] WatchError),
30 #[error(transparent)]
31 InitError(#[from] InitError),
32 #[error(transparent)]
33 NewError(#[from] NewError),
34 #[error(transparent)]
35 InstallError(#[from] InstallError),
36}
37
38#[derive(Error, Debug)]
41pub enum ExecutionError {
42 #[error("couldn't execute command '{cmd}' (this doesn't mean it threw an error, it means it couldn't be run at all)")]
43 CmdExecFailed {
44 cmd: String,
45 #[source]
46 source: std::io::Error,
47 },
48 #[error("couldn't execute command because it prematurely stopped reporting (if this persists, please report it as a bug)")]
49 NextStdoutLineNone,
50 #[error("couldn't get path to server executable (if this persists, please report it as a bug, especially if you've just updated `cargo`)")]
51 GetServerExecutableFailed {
52 #[source]
53 source: serde_json::Error,
54 },
55 #[error("couldn't get path to server executable (if this persists, try `perseus clean`)")]
56 GetServerExecutableFailedSimple,
57 #[error("expected second-last message from Cargo to contain server executable path, none existed (too few messages) (report this as a bug if it persists)")]
58 ServerExecutableMsgNotFound,
59 #[error("couldn't parse server executable path from Cargo (report this as a bug if it persists): {err}")]
60 ParseServerExecutableFailed { err: String },
61 #[error("couldn't remove and replace internal build artifact directory '{target:?}' (run `perseus clean` if this persists)")]
62 RemoveArtifactsFailed {
63 target: Option<String>,
64 #[source]
65 source: std::io::Error,
66 },
67 #[error("failed to wait on thread (please report this as a bug if it persists)")]
68 ThreadWaitFailed,
69 #[error("value in `PORT` environment variable couldn't be parsed as a number")]
70 PortNotNumber {
71 #[source]
72 source: std::num::ParseIntError,
73 },
74 #[error("couldn't parse `Cargo.toml` (are you running in the right directory?)")]
75 GetManifestFailed {
76 #[source]
77 source: cargo_toml::Error,
78 },
79 #[error("couldn't get crate name from `[package]` section of `Cargo.toml` (are you running in the right directory?)")]
80 CrateNameNotPresentInManifest,
81 #[error("couldn't create directory for distribution artifacts (do you have the necessary permissions?)")]
82 CreateDistFailed {
83 #[source]
84 source: std::io::Error,
85 },
86}
87
88#[derive(Error, Debug)]
90pub enum ExportError {
91 #[error("couldn't create directory structure necessary for exporting (do you have the necessary permissions?)")]
92 DirStructureCreationFailed {
93 #[source]
94 source: std::io::Error,
95 },
96 #[error("couldn't copy asset from '{from}' to '{to}' for exporting")]
97 MoveAssetFailed {
98 to: String,
99 from: String,
100 #[source]
101 source: std::io::Error,
102 },
103 #[error("couldn't copy directory from '{from}' to '{to}' for exporting")]
104 MoveDirFailed {
105 to: String,
106 from: String,
107 #[source]
108 source: fs_extra::error::Error,
109 },
110 #[error(transparent)]
112 ExecutionError(#[from] ExecutionError),
113}
114
115#[derive(Error, Debug)]
117pub enum DeployError {
118 #[error("couldn't copy exported static files from '{from:?}' to '{to}'")]
119 MoveExportDirFailed {
120 to: String,
121 from: String,
122 #[source]
123 source: fs_extra::error::Error,
124 },
125 #[error("couldn't delete and recreate output directory '{path}'")]
126 ReplaceOutputDirFailed {
127 path: String,
128 #[source]
129 source: std::io::Error,
130 },
131 #[error("couldn't copy file from '{from}' to '{to}' for deployment packaging")]
132 MoveAssetFailed {
133 to: String,
134 from: String,
135 #[source]
136 source: std::io::Error,
137 },
138 #[error("couldn't copy directory from '{from}' to '{to}' for deployment packaging")]
139 MoveDirFailed {
140 to: String,
141 from: String,
142 #[source]
143 source: fs_extra::error::Error,
144 },
145 #[error("couldn't read contents of export directory '{path}' for packaging (if this persists, try `perseus clean`)")]
146 ReadExportDirFailed {
147 path: String,
148 #[source]
149 source: std::io::Error,
150 },
151 #[error("couldn't create distribution artifacts directory for deployment (if this persists, try `perseus clean`)")]
152 CreateDistDirFailed {
153 #[source]
154 source: std::io::Error,
155 },
156 #[error("failed to minify javascript bundle (this is probably an upstream bug, re-try with `--no-minify-js`)")]
157 MinifyError {
158 #[source]
159 source: minify_js::MinifyError,
160 },
161 #[error("minified js was not utf-8 (this is a bug, re-try with `--no-minify-js` for now)")]
162 MinifyNotUtf8 {
163 #[source]
164 source: std::string::FromUtf8Error,
165 },
166 #[error("failed to read unminified js (if this persists, try `perseus clean`)")]
167 ReadUnminifiedJsFailed {
168 #[source]
169 source: std::io::Error,
170 },
171 #[error("failed to write minified js (if this persists, try `perseus clean`)")]
172 WriteMinifiedJsFailed {
173 #[source]
174 source: std::io::Error,
175 },
176}
177
178#[derive(Error, Debug)]
179pub enum WatchError {
180 #[error("couldn't set up a file watcher, try re-running this command")]
181 WatcherSetupFailed {
182 #[source]
183 source: notify::Error,
184 },
185 #[error("couldn't read your current directory to watch files, do you have the necessary permissions?")]
186 ReadCurrentDirFailed {
187 #[source]
188 source: std::io::Error,
189 },
190 #[error("couldn't read entry in your current directory, try re-running this command")]
191 ReadDirEntryFailed {
192 #[source]
193 source: std::io::Error,
194 },
195 #[error("the file/folder '{filename}' could not be resolved to an absolute path (does the file/folder exist?)")]
196 WatchFileNotResolved {
197 filename: String,
198 source: std::io::Error,
199 },
200 #[error("couldn't watch file at '{filename}', try re-running the command")]
201 WatchFileFailed {
202 filename: String,
203 #[source]
204 source: notify::Error,
205 },
206 #[error("couldn't unwatch file at '{filename}', try re-running the command")]
207 UnwatchFileFailed {
208 filename: String,
209 #[source]
210 source: notify::Error,
211 },
212 #[error("an error occurred while watching files")]
213 WatcherError {
214 #[source]
215 source: std::sync::mpsc::RecvError,
216 },
217 #[error("couldn't spawn a child process to build your app in watcher mode")]
218 SpawnSelfFailed {
219 #[source]
220 source: std::io::Error,
221 },
222 #[error("couldn't get the path to the cli's executable, try re-running the command")]
223 GetSelfPathFailed {
224 #[source]
225 source: std::io::Error,
226 },
227 #[error("couldn't read an entry in the targeted custom directory for watching, do you have the necessary permissions?")]
228 ReadCustomDirEntryFailed {
229 #[source]
230 source: walkdir::Error,
231 },
232}
233
234#[derive(Error, Debug)]
235pub enum InitError {
236 #[error("couldn't create directory structure for new project, do you have the necessary permissions?")]
237 CreateDirStructureFailed {
238 #[source]
239 source: std::io::Error,
240 },
241 #[error("couldn't create file '{filename}' for project initialization")]
242 CreateInitFileFailed {
243 #[source]
244 source: std::io::Error,
245 filename: String,
246 },
247}
248
249#[derive(Error, Debug)]
250pub enum NewError {
251 #[error(transparent)]
253 InitError(#[from] InitError),
254 #[error("couldn't create directory for new project, do you have the necessary permissions?")]
255 CreateProjectDirFailed {
256 #[source]
257 source: std::io::Error,
258 },
259 #[error("fetching the custom initialization template failed")]
260 GetCustomInitFailed {
261 #[source]
262 source: ExecutionError,
263 },
264 #[error(
265 "fetching the custom initialization template returned non-zero exit code ({exit_code})"
266 )]
267 GetCustomInitNonZeroExitCode { exit_code: i32 },
268 #[error(
269 "couldn't remove git internals at '{target_dir:?}' for custom initialization template"
270 )]
271 RemoveCustomInitGitFailed {
272 target_dir: Option<String>,
273 #[source]
274 source: std::io::Error,
275 },
276}
277
278#[derive(Error, Debug)]
279pub enum InstallError {
280 #[error("couldn't create `dist/tools/` for external dependency installation")]
281 CreateToolsDirFailed {
282 #[source]
283 source: std::io::Error,
284 },
285 #[error("couldn't install '{tool}', as there are no precompiled binaries for your platform and it's not currently installed; please install this tool manually (see https://framesurge.sh/perseus/en-US/docs/0.4.x/reference/faq)")]
288 ExternalToolUnavailable {
289 tool: String,
290 #[source]
292 source: std::io::Error,
293 },
294 #[error("couldn't download binary for '{tool}' (do you have an internet connection?)")]
295 BinaryDownloadRequestFailed {
296 tool: String,
297 #[source]
298 source: reqwest::Error,
299 },
300 #[error(
301 "couldn't create destination for tool download (do you have the necessary permissions?)"
302 )]
303 CreateToolDownloadDestFailed {
304 #[source]
305 source: tokio::io::Error,
306 },
307 #[error("couldn't chunk tool download properly (do you have an internet connection?)")]
308 ChunkBinaryDownloadFailed {
309 #[source]
310 source: reqwest::Error,
311 },
312 #[error(
313 "couldn't write downloaded chunk of external tool (do you have the necessary permissions?)"
314 )]
315 WriteBinaryDownloadChunkFailed {
316 #[source]
317 source: tokio::io::Error,
318 },
319 #[error("couldn't determine latest version of '{tool}' (do you have an internet connection?)")]
320 GetLatestToolVersionFailed {
321 tool: String,
322 #[source]
323 source: reqwest::Error,
324 },
325 #[error("couldn't parse latest version of '{tool}' (if this error persists, please report it as a bug)")]
326 ParseToolVersionFailed { tool: String },
327 #[error("couldn't create destination for extraction of external tool (do you have the necessary permissions?)")]
328 CreateToolExtractDestFailed {
329 #[source]
330 source: std::io::Error,
331 },
332 #[error("couldn't extract '{tool}' (do you have the necessary permissions?)")]
333 ToolExtractFailed {
334 tool: String,
335 #[source]
336 source: std::io::Error,
337 },
338 #[error("couldn't delete archive from tool deletion")]
339 ArchiveDeletionFailed {
340 #[source]
341 source: std::io::Error,
342 },
343 #[error("couldn't rename directory for external tool binaries")]
344 DirRenameFailed {
345 #[source]
346 source: std::io::Error,
347 },
348 #[error("couldn't read `dist/tools/` to determine which tool versions were installed (do you have the necessary permissions?)")]
349 ReadToolsDirFailed {
350 #[source]
351 source: std::io::Error,
352 },
353 #[error("directory found in `dist/tools/` with invalid name (running `perseus clean` should resolve this)")]
354 InvalidToolsDirName { name: String },
355 #[error("generating `Cargo.lock` returned non-zero exit code")]
356 LockfileGenerationNonZero { code: i32 },
357 #[error("couldn't generate `Cargo.lock`")]
358 LockfileGenerationFailed {
359 #[source]
360 source: ExecutionError,
361 },
362 #[error("couldn't fetch metadata for current crate (have you run `perseus init` yet?)")]
363 MetadataFailed {
364 #[source]
365 source: cargo_metadata::Error,
366 },
367 #[error("couldn't load `Cargo.lock` from workspace root")]
368 LockfileLoadFailed {
369 #[source]
370 source: cargo_lock::Error,
371 },
372}