1pub mod config;
4pub mod error;
5
6pub use config::Config;
7pub use error::ConfigError;
8
9use std::path::Path;
10
11pub fn load(start: &Path) -> Result<Config, ConfigError> {
18 for ancestor in start.ancestors() {
19 let aiproofrc = ancestor.join(".aiproofrc");
20 if aiproofrc.is_file() {
21 return load_aiproofrc(&aiproofrc);
22 }
23 let pyproject = ancestor.join("pyproject.toml");
24 if pyproject.is_file()
25 && let Some(cfg) = try_pyproject(&pyproject)?
26 {
27 return Ok(cfg);
28 }
29 }
30 Ok(Config::default())
31}
32
33fn load_aiproofrc(path: &Path) -> Result<Config, ConfigError> {
34 let text = std::fs::read_to_string(path).map_err(|source| ConfigError::Io {
35 path: path.display().to_string(),
36 source,
37 })?;
38 toml::from_str::<Config>(&text).map_err(|e| ConfigError::Toml {
39 path: path.display().to_string(),
40 message: e.to_string(),
41 })
42}
43
44fn try_pyproject(path: &Path) -> Result<Option<Config>, ConfigError> {
45 let text = std::fs::read_to_string(path).map_err(|source| ConfigError::Io {
46 path: path.display().to_string(),
47 source,
48 })?;
49 let value: toml::Value = text
50 .parse()
51 .map_err(|e: toml::de::Error| ConfigError::Toml {
52 path: path.display().to_string(),
53 message: e.to_string(),
54 })?;
55 let Some(table) = value.get("tool").and_then(|t| t.get("aiproof")) else {
56 return Ok(None);
57 };
58 let serialized = toml::to_string_pretty(table).map_err(|e| ConfigError::Toml {
59 path: path.display().to_string(),
60 message: e.to_string(),
61 })?;
62 toml::from_str::<Config>(&serialized)
63 .map(Some)
64 .map_err(|e| ConfigError::Toml {
65 path: path.display().to_string(),
66 message: format!("in [tool.aiproof]: {e}"),
67 })
68}