Skip to main content

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}