codex_patcher/config/
loader.rs1use crate::config::schema::{PatchConfig, ValidationError};
2use std::fmt;
3use std::fs;
4use std::path::{Path, PathBuf};
5
6#[derive(Debug)]
7pub enum ConfigError {
8 Io {
9 path: PathBuf,
10 source: std::io::Error,
11 },
12 Toml {
13 path: Option<PathBuf>,
14 source: toml_edit::de::Error,
15 },
16 Validation {
17 path: Option<PathBuf>,
18 source: ValidationError,
19 },
20}
21
22impl ConfigError {
23 fn with_path(self, path: &Path) -> Self {
24 let path = path.to_path_buf();
25 match self {
26 ConfigError::Io { .. } => self,
27 ConfigError::Toml { path: None, source } => ConfigError::Toml {
28 path: Some(path),
29 source,
30 },
31 ConfigError::Validation { path: None, source } => ConfigError::Validation {
32 path: Some(path),
33 source,
34 },
35 other => other,
36 }
37 }
38}
39
40impl fmt::Display for ConfigError {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 ConfigError::Io { path, source } => {
44 write!(
45 f,
46 "failed to read patch config from {}: {}",
47 path.display(),
48 source
49 )
50 }
51 ConfigError::Toml { path, source } => match path {
52 Some(path) => write!(
53 f,
54 "failed to parse patch config TOML ({}): {}",
55 path.display(),
56 source
57 ),
58 None => write!(f, "failed to parse patch config TOML: {}", source),
59 },
60 ConfigError::Validation { path, source } => match path {
61 Some(path) => write!(f, "invalid patch config ({}): {}", path.display(), source),
62 None => write!(f, "invalid patch config: {}", source),
63 },
64 }
65 }
66}
67
68impl std::error::Error for ConfigError {
69 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
70 match self {
71 ConfigError::Io { source, .. } => Some(source),
72 ConfigError::Toml { source, .. } => Some(source),
73 ConfigError::Validation { source, .. } => Some(source),
74 }
75 }
76}
77
78pub fn load_from_str(input: &str) -> Result<PatchConfig, ConfigError> {
79 let config: PatchConfig = toml_edit::de::from_str(input)
80 .map_err(|source| ConfigError::Toml { path: None, source })?;
81 config
82 .validate()
83 .map_err(|source| ConfigError::Validation { path: None, source })?;
84 Ok(config)
85}
86
87pub fn load_from_path(path: impl AsRef<Path>) -> Result<PatchConfig, ConfigError> {
88 let path = path.as_ref();
89 let contents = fs::read_to_string(path).map_err(|source| ConfigError::Io {
90 path: path.to_path_buf(),
91 source,
92 })?;
93 load_from_str(&contents).map_err(|error| error.with_path(path))
94}