Skip to content

Commit acc0ccf

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

1 file changed

Lines changed: 80 additions & 43 deletions

File tree

agent-control/src/agent_control/config.rs

Lines changed: 80 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,75 @@ 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+
/// For example, given the following GlobalDefaults:
127+
/// ```
128+
/// GlobalDefaults {
129+
/// oci: OciConfig {
130+
/// registry: "docker.io".to_string(),
131+
/// auth: OciAuth {
132+
/// basic: BasicAuth {
133+
/// username: "user".to_string(),
134+
/// password: "pass".to_string(),
135+
/// },
136+
/// bearer: "".to_string(),
137+
/// }
138+
/// ```
139+
///
140+
/// This function will produce the following HashMap:
141+
/// ```
142+
/// {
143+
/// "oci.registry": "docker.io",
144+
/// "oci.auth.basic.username": "user",
145+
/// "oci.auth.basic.password": "pass",
146+
/// "oci.auth.bearer": "",
147+
/// }
148+
fn to_hashmap(&self) -> HashMap<String, serde_yaml::Value> {
149+
let value = serde_yaml::to_value(self).expect("GlobalDefaults should serialize to YAML");
150+
151+
let mut result = HashMap::new();
152+
153+
if let serde_yaml::Value::Mapping(map) = value {
154+
for (key, val) in map {
155+
if let Some(key_str) = key.as_str() {
156+
flatten_value(key_str, &val, &mut result);
157+
}
158+
}
159+
}
160+
161+
result
162+
}
163+
}
164+
165+
fn flatten_value(
166+
prefix: &str,
167+
value: &serde_yaml::Value,
168+
result: &mut HashMap<String, serde_yaml::Value>,
169+
) {
170+
match value {
171+
serde_yaml::Value::Mapping(map) => {
172+
for (key, val) in map {
173+
if let Some(key_str) = key.as_str() {
174+
let new_prefix = format!("{}.{}", prefix, key_str);
175+
flatten_value(&new_prefix, val, result);
176+
}
177+
}
178+
}
179+
_ => {
180+
result.insert(prefix.to_string(), value.clone());
181+
}
182+
}
183+
}
184+
185+
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
124186
pub struct OciConfig {
125187
#[serde(default = "OciConfig::default_registry")]
126188
registry: String,
@@ -143,42 +205,15 @@ impl OciConfig {
143205
}
144206
}
145207

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)]
208+
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
174209
struct OciAuth {
175210
#[serde(default)]
176211
basic: BasicAuth,
177212
#[serde(default)]
178213
bearer: String,
179214
}
180215

181-
#[derive(Debug, Deserialize, Default, Clone, PartialEq)]
216+
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
182217
struct BasicAuth {
183218
username: String,
184219
password: String,
@@ -1177,8 +1212,8 @@ k8s:
11771212
}
11781213

11791214
#[test]
1180-
fn test_oci_config_default_values() {
1181-
let vars = OciConfig::default().to_hashmap();
1215+
fn test_global_defaults_base_values() {
1216+
let vars = GlobalDefaults::default().to_hashmap();
11821217
assert_eq!(vars.len(), 4);
11831218
assert!(vars.get("oci.registry").is_some_and(|v| v == "docker.io"));
11841219
assert!(vars.get("oci.auth.basic.username").is_some_and(|v| v == ""));
@@ -1187,19 +1222,21 @@ k8s:
11871222
}
11881223

11891224
#[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(),
1225+
fn test_global_defaults_provided_values() {
1226+
let global_defaults = GlobalDefaults {
1227+
oci: OciConfig {
1228+
registry: "custom.docker.io".to_string(),
1229+
auth: OciAuth {
1230+
basic: BasicAuth {
1231+
username: "user".to_string(),
1232+
password: "pass".to_string(),
1233+
},
1234+
bearer: "token".to_string(),
11971235
},
1198-
bearer: "token".to_string(),
11991236
},
12001237
};
12011238

1202-
let vars = oci_config.to_hashmap();
1239+
let vars = global_defaults.to_hashmap();
12031240
assert_eq!(vars.len(), 4);
12041241
assert!(
12051242
vars.get("oci.registry")

0 commit comments

Comments
 (0)