Skip to content

Commit bd3c3e4

Browse files
feat: automate default hashmap generation
1 parent 70fa907 commit bd3c3e4

1 file changed

Lines changed: 85 additions & 43 deletions

File tree

agent-control/src/agent_control/config.rs

Lines changed: 85 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pub struct AgentControlConfig {
9494

9595
impl AgentControlConfig {
9696
pub fn defaults(&self) -> HashMap<String, serde_yaml::Value> {
97-
self.global_defaults.oci.to_hashmap()
97+
self.global_defaults.to_hashmap()
9898
}
9999
}
100100

@@ -114,13 +114,80 @@ pub struct PackagesConfig {
114114
pub signature_verification_enabled: SignatureVerificationEnabled,
115115
}
116116

117-
#[derive(Debug, Deserialize, Default, Clone, PartialEq)]
117+
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
118118
pub struct GlobalDefaults {
119119
#[serde(default)]
120120
oci: OciConfig,
121121
}
122122

123-
#[derive(Debug, Deserialize, Clone, PartialEq)]
123+
impl GlobalDefaults {
124+
/// Flattens the nested structure of GlobalDefaults into a single level HashMap with dot-separated keys.
125+
///
126+
/// # Example
127+
///
128+
/// Given the following GlobalDefaults structure:
129+
/// ```ignore
130+
/// GlobalDefaults {
131+
/// oci: OciConfig {
132+
/// registry: "docker.io",
133+
/// auth: OciAuth {
134+
/// basic: BasicAuth {
135+
/// username: "user",
136+
/// password: "pass",
137+
/// },
138+
/// bearer: "",
139+
/// },
140+
/// }
141+
/// }
142+
/// ```
143+
///
144+
/// we get the following HashMap:
145+
/// ```ignore
146+
/// {
147+
/// "oci.registry": "docker.io",
148+
/// "oci.auth.basic.username": "user",
149+
/// "oci.auth.basic.password": "pass",
150+
/// "oci.auth.bearer": "",
151+
/// }
152+
/// ```
153+
fn to_hashmap(&self) -> HashMap<String, serde_yaml::Value> {
154+
let value = serde_yaml::to_value(self).expect("GlobalDefaults should serialize to YAML");
155+
156+
let mut result = HashMap::new();
157+
158+
if let serde_yaml::Value::Mapping(map) = value {
159+
for (key, val) in map {
160+
if let Some(key_str) = key.as_str() {
161+
flatten_value(key_str, &val, &mut result);
162+
}
163+
}
164+
}
165+
166+
result
167+
}
168+
}
169+
170+
fn flatten_value(
171+
prefix: &str,
172+
value: &serde_yaml::Value,
173+
result: &mut HashMap<String, serde_yaml::Value>,
174+
) {
175+
match value {
176+
serde_yaml::Value::Mapping(map) => {
177+
for (key, val) in map {
178+
if let Some(key_str) = key.as_str() {
179+
let new_prefix = format!("{}.{}", prefix, key_str);
180+
flatten_value(&new_prefix, val, result);
181+
}
182+
}
183+
}
184+
_ => {
185+
result.insert(prefix.to_string(), value.clone());
186+
}
187+
}
188+
}
189+
190+
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
124191
pub struct OciConfig {
125192
#[serde(default = "OciConfig::default_registry")]
126193
registry: String,
@@ -143,42 +210,15 @@ impl OciConfig {
143210
}
144211
}
145212

146-
impl OciConfig {
147-
fn to_hashmap(&self) -> HashMap<String, serde_yaml::Value> {
148-
let mut vars = HashMap::new();
149-
150-
vars.insert(
151-
"oci.registry".to_string(),
152-
serde_yaml::Value::String(self.registry.clone()),
153-
);
154-
155-
vars.insert(
156-
"oci.auth.basic.username".to_string(),
157-
serde_yaml::Value::String(self.auth.basic.username.clone()),
158-
);
159-
vars.insert(
160-
"oci.auth.basic.password".to_string(),
161-
serde_yaml::Value::String(self.auth.basic.password.clone()),
162-
);
163-
164-
vars.insert(
165-
"oci.auth.bearer".to_string(),
166-
serde_yaml::Value::String(self.auth.bearer.clone()),
167-
);
168-
169-
vars
170-
}
171-
}
172-
173-
#[derive(Debug, Deserialize, Default, Clone, PartialEq)]
213+
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
174214
struct OciAuth {
175215
#[serde(default)]
176216
basic: BasicAuth,
177217
#[serde(default)]
178218
bearer: String,
179219
}
180220

181-
#[derive(Debug, Deserialize, Default, Clone, PartialEq)]
221+
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
182222
struct BasicAuth {
183223
username: String,
184224
password: String,
@@ -1177,8 +1217,8 @@ k8s:
11771217
}
11781218

11791219
#[test]
1180-
fn test_oci_config_default_values() {
1181-
let vars = OciConfig::default().to_hashmap();
1220+
fn test_global_defaults_base_values() {
1221+
let vars = GlobalDefaults::default().to_hashmap();
11821222
assert_eq!(vars.len(), 4);
11831223
assert!(vars.get("oci.registry").is_some_and(|v| v == "docker.io"));
11841224
assert!(vars.get("oci.auth.basic.username").is_some_and(|v| v == ""));
@@ -1187,19 +1227,21 @@ k8s:
11871227
}
11881228

11891229
#[test]
1190-
fn test_oci_config_provided_values() {
1191-
let oci_config = OciConfig {
1192-
registry: "custom.docker.io".to_string(),
1193-
auth: OciAuth {
1194-
basic: BasicAuth {
1195-
username: "user".to_string(),
1196-
password: "pass".to_string(),
1230+
fn test_global_defaults_provided_values() {
1231+
let global_defaults = GlobalDefaults {
1232+
oci: OciConfig {
1233+
registry: "custom.docker.io".to_string(),
1234+
auth: OciAuth {
1235+
basic: BasicAuth {
1236+
username: "user".to_string(),
1237+
password: "pass".to_string(),
1238+
},
1239+
bearer: "token".to_string(),
11971240
},
1198-
bearer: "token".to_string(),
11991241
},
12001242
};
12011243

1202-
let vars = oci_config.to_hashmap();
1244+
let vars = global_defaults.to_hashmap();
12031245
assert_eq!(vars.len(), 4);
12041246
assert!(
12051247
vars.get("oci.registry")

0 commit comments

Comments
 (0)