1use std::{io, path::PathBuf};
2
3use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, WithWatchError>;
6
7#[derive(Debug, Error)]
8pub enum WithWatchError {
9 #[error(
10 "Provide a delegated utility, `--shell <expr>`, or `exec --input <glob>... -- <command> \
11 ...`."
12 )]
13 MissingCommand,
14 #[error("`--shell` cannot be combined with delegated argv or the `exec` subcommand.")]
15 ConflictingModes,
16 #[error("`--shell` requires a non-empty shell expression.")]
17 EmptyShellExpression,
18 #[error("`exec` requires a delegated command after `--`.")]
19 MissingExecCommand,
20 #[error(
21 "No watch inputs could be inferred from the delegated command. Use `with-watch exec \
22 --input <glob>... -- <command> [args...]`."
23 )]
24 NoWatchInputs,
25 #[error("Failed to determine the current working directory: {0}")]
26 CurrentDirectory(#[source] io::Error),
27 #[error("Failed to parse shell expression: {message}")]
28 ShellParse { message: String },
29 #[error("Shell control-flow is out of scope for with-watch v1: {construct}")]
30 UnsupportedShellConstruct { construct: String },
31 #[error("Failed to compile glob pattern `{pattern}`: {message}")]
32 InvalidGlob { pattern: String, message: String },
33 #[error("Could not derive a watch anchor for `{path}`.")]
34 MissingWatchAnchor { path: PathBuf },
35 #[error("Failed to read metadata for `{path}`: {source}")]
36 Metadata {
37 path: PathBuf,
38 #[source]
39 source: io::Error,
40 },
41 #[error("Failed to read `{path}` while hashing: {source}")]
42 HashRead {
43 path: PathBuf,
44 #[source]
45 source: io::Error,
46 },
47 #[error("Failed to create a filesystem watcher: {0}")]
48 WatcherCreate(#[source] notify::Error),
49 #[error("Failed to watch `{path}` recursively: {source}")]
50 WatchPath {
51 path: PathBuf,
52 #[source]
53 source: notify::Error,
54 },
55 #[error("Failed to spawn `{command}`: {source}")]
56 Spawn {
57 command: String,
58 #[source]
59 source: io::Error,
60 },
61 #[error("Failed while waiting for `{command}`: {source}")]
62 Wait {
63 command: String,
64 #[source]
65 source: io::Error,
66 },
67 #[error("Failed to refresh stdout before running the delegated command: {0}")]
68 StdoutRefresh(#[source] io::Error),
69 #[error("`--shell` execution is only supported on Unix-like platforms.")]
70 UnsupportedShellPlatform,
71}
72
73impl WithWatchError {
74 pub fn exit_code(&self) -> i32 {
75 match self {
76 Self::MissingCommand
77 | Self::ConflictingModes
78 | Self::EmptyShellExpression
79 | Self::MissingExecCommand
80 | Self::NoWatchInputs
81 | Self::ShellParse { .. }
82 | Self::UnsupportedShellConstruct { .. }
83 | Self::InvalidGlob { .. }
84 | Self::MissingWatchAnchor { .. }
85 | Self::UnsupportedShellPlatform => 2,
86 Self::CurrentDirectory(_)
87 | Self::Metadata { .. }
88 | Self::HashRead { .. }
89 | Self::WatcherCreate(_)
90 | Self::WatchPath { .. }
91 | Self::Spawn { .. }
92 | Self::Wait { .. }
93 | Self::StdoutRefresh(_) => 1,
94 }
95 }
96}