From 1d8c03132fca75b30e78dcf59aa10dbe6015655e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Wed, 17 Dec 2025 23:42:33 +0000 Subject: [PATCH] Merge the storage config --- rust/agama-utils/src/api/storage/config.rs | 74 +++++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/rust/agama-utils/src/api/storage/config.rs b/rust/agama-utils/src/api/storage/config.rs index 3a3719ccaa..6b0dc96a7e 100644 --- a/rust/agama-utils/src/api/storage/config.rs +++ b/rust/agama-utils/src/api/storage/config.rs @@ -22,14 +22,12 @@ use merge::Merge; use serde::{Deserialize, Serialize}; use serde_json::Value; -#[derive(Clone, Debug, Default, Serialize, Deserialize, Merge, utoipa::ToSchema)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, utoipa::ToSchema)] #[serde(rename_all = "camelCase")] pub struct Config { #[serde(skip_serializing_if = "Option::is_none")] - #[merge(strategy = merge::option::overwrite_none)] pub storage: Option, #[serde(skip_serializing_if = "Option::is_none")] - #[merge(strategy = merge::option::overwrite_none)] pub legacy_autoyast_storage: Option, } @@ -38,3 +36,73 @@ impl Config { self.storage.is_some() || self.legacy_autoyast_storage.is_some() } } + +impl Merge for Config { + fn merge(&mut self, other: Self) { + if let Some(storage) = &mut self.storage { + if let Some(other_storage) = other.storage { + merge_values_as_objects(storage, other_storage); + } + } else { + self.storage = other.storage; + } + + // No need to merge both values because it is just an array of drives. + if self.legacy_autoyast_storage.is_none() { + self.legacy_autoyast_storage = other.legacy_autoyast_storage; + } + } +} + +// Merge to serde_json::Value structs. +// +// Both Value structs are supposed to represent JSON objects. +fn merge_values_as_objects(left: &mut Value, right: Value) { + let Value::Object(left_object) = left else { + return; + }; + + let Value::Object(right_object) = right else { + return; + }; + + for (k, v) in right_object { + left_object.entry(k).or_insert(v); + } +} + +#[cfg(test)] +mod tests { + use merge::Merge; + + use super::*; + + #[test] + fn test_merge_with_default_config() { + let mut config: Config = serde_json::from_str(r#"{ "storage": { "drives": [] }}"#).unwrap(); + let original = Config::default(); + + config.merge(original); + assert!(config.storage.is_some()); + } + + #[test] + fn test_merge_storage_key() { + let mut config: Config = serde_json::from_str(r#"{ "storage": { "drives": [] }}"#).unwrap(); + let original: Config = serde_json::from_str(r#"{ "storage": { "mdRaids": [] }}"#).unwrap(); + + config.merge(original); + let value = config.storage.unwrap(); + assert!(value.get("drives").is_some()); + assert!(value.get("mdRaids").is_some()); + } + + #[test] + fn test_merge_with_no_storage() { + let mut config = Config::default(); + let original: Config = serde_json::from_str(r#"{ "storage": { "drives": [] }}"#).unwrap(); + + config.merge(original); + assert!(config.storage.is_some()); + } +}