onetaskgraph_core/config/error.rs
1//! What goes wrong while loading a configuration, and what to do about it.
2
3use std::path::{Path, PathBuf};
4
5/// A configuration this product will not run on.
6///
7/// Every variant names the thing a user has to go and change and says what to change
8/// it to. That is the whole point: an unknown field, a bad value, an unknown plugin
9/// name and an unusable source name are all *usage* errors here, never settings that
10/// get quietly dropped.
11#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
12pub enum ConfigError {
13 /// A configuration document exists but could not be read.
14 #[error(
15 "could not read {}: {message}\n\
16 next: make that file readable, or remove it so the layer beneath it is used.",
17 path.display()
18 )]
19 Read {
20 /// The document that could not be read.
21 path: PathBuf,
22 /// What the filesystem said.
23 message: String,
24 },
25
26 /// A configuration document is not valid YAML.
27 #[error(
28 "{}: not valid YAML: {message}\n\
29 next: correct the syntax at the position named above, then re-run.",
30 path.display()
31 )]
32 Syntax {
33 /// The document that would not parse.
34 path: PathBuf,
35 /// What the parser said, position included.
36 message: String,
37 },
38
39 /// One setting is unknown, or its value is not usable.
40 ///
41 /// `key` is the dotted path a user can search their configuration for and is also
42 /// the path the environment-variable and `--set` spellings are derived from, so
43 /// one name locates the problem at whichever layer set it.
44 #[error("{key}: {message}\nnext: {next}")]
45 Setting {
46 /// The dotted path of the offending setting.
47 key: String,
48 /// What is wrong with it.
49 message: String,
50 /// The concrete next action.
51 next: String,
52 },
53}
54
55impl ConfigError {
56 /// A [`ConfigError::Setting`] over `key`.
57 pub(crate) fn setting(
58 key: impl Into<String>,
59 message: impl Into<String>,
60 next: impl Into<String>,
61 ) -> Self {
62 Self::Setting {
63 key: key.into(),
64 message: message.into(),
65 next: next.into(),
66 }
67 }
68
69 /// A [`ConfigError::Read`] over `path`.
70 pub(crate) fn read(path: &Path, error: &std::io::Error) -> Self {
71 Self::Read {
72 path: path.to_path_buf(),
73 message: error.to_string(),
74 }
75 }
76
77 /// The dotted key this error names, when it names one.
78 #[must_use]
79 pub fn key(&self) -> Option<&str> {
80 match self {
81 Self::Setting { key, .. } => Some(key),
82 Self::Read { .. } | Self::Syntax { .. } => None,
83 }
84 }
85}