mongodb_atlas_cli/config/source/
mod.rs1use std::{
2 collections::HashMap,
3 path::{Path, PathBuf},
4};
5
6use config::{ConfigError, Value, ValueKind};
7pub use global::AtlasCLIGlobalConfigSource;
8pub use profile::AtlasCLIProfileConfigSource;
9
10pub mod global;
11pub mod profile;
12
13#[derive(thiserror::Error, Debug)]
14pub enum AtlasCLIConfigSourceError {
15 #[error("Failed to read file: {0}")]
16 FailedToReadFile(PathBuf, std::io::Error),
17
18 #[error("Failed to parse TOML: {0}")]
19 FailedToParseTOML(#[from] toml::de::Error),
20
21 #[error("Invalid root, was expecting table")]
22 InvalidRootExpectedTable,
23
24 #[error("Invalid profile, was expecting table")]
25 InvalidProfileExpectedTable,
26}
27
28impl From<AtlasCLIConfigSourceError> for ConfigError {
29 fn from(error: AtlasCLIConfigSourceError) -> Self {
30 ConfigError::Foreign(Box::new(error))
31 }
32}
33
34fn config_value_from_toml_file(
35 origin: impl Into<String>,
36 source: impl AsRef<Path>,
37 root_extractor: impl FnOnce(toml::Table) -> Result<toml::Table, AtlasCLIConfigSourceError>,
38) -> Result<HashMap<String, Value>, AtlasCLIConfigSourceError> {
39 let source = source.as_ref();
40 let origin = origin.into();
41
42 let file_content = std::fs::read_to_string(source)
44 .map_err(|e| AtlasCLIConfigSourceError::FailedToReadFile(source.to_path_buf(), e))?;
45
46 let toml_config: toml::Value =
48 toml::from_str(&file_content).map_err(AtlasCLIConfigSourceError::FailedToParseTOML)?;
49
50 let toml::Value::Table(toml_root) = toml_config else {
52 return Err(AtlasCLIConfigSourceError::InvalidRootExpectedTable);
53 };
54
55 let root = root_extractor(toml_root)?;
57
58 let mut config_value = HashMap::new();
60 for (key, value) in root {
61 let value_kind = match value {
62 toml::Value::String(s) => Some(ValueKind::String(s.clone())),
63 toml::Value::Integer(i) => Some(ValueKind::I64(i)),
64 toml::Value::Float(f) => Some(ValueKind::Float(f)),
65 toml::Value::Boolean(b) => Some(ValueKind::Boolean(b)),
66 toml::Value::Array(_) | toml::Value::Datetime(_) | toml::Value::Table(_) => {
67 None
69 }
70 };
71
72 if let Some(value_kind) = value_kind {
73 config_value.insert(key.to_string(), Value::new(Some(&origin), value_kind));
74 }
75 }
76
77 Ok(config_value)
78}