-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(configurationParser): moves the MergeYamlNodes method to an exte…
…rnal function, added some UTs for the new MergeYamlNodes function
- Loading branch information
Showing
7 changed files
with
292 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
src/agent/configuration_parser/include/configuration_parser_utils.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#pragma once | ||
|
||
#include <yaml-cpp/yaml.h> | ||
|
||
/// @brief Merges two YAML nodes, modifying the baseYaml node to include or additionalYaml values from the | ||
/// additionalYaml node. | ||
/// | ||
/// This function traverses the two YAML nodes. If a key exists in both nodes: | ||
/// - If both values are maps, the function recurses to merge their content. | ||
/// - If both values are sequences, their elements are concatenated. | ||
/// - In all other cases (scalars, aliases, null values), the value from the additionalYaml node replaces the value in | ||
/// the baseYaml node. If a key only exists in the additionalYaml node, it is added to the baseYaml node. | ||
/// | ||
/// @param baseYaml Reference to the baseYaml YAML::Node that will be modified. | ||
/// @param additionalYaml Const reference to the YAML::Node containing values to merge into the baseYaml. | ||
void MergeYamlNodes(YAML::Node& baseYaml, const YAML::Node& additionalYaml); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
src/agent/configuration_parser/src/configuration_parser_utils.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#include <configuration_parser_utils.hpp> | ||
#include <queue> | ||
#include <unordered_set> | ||
|
||
void MergeYamlNodes(YAML::Node& baseYaml, const YAML::Node& additionalYaml) | ||
{ | ||
// Queue to manage nodes to be merged. Pairs of nodes are handled directly. | ||
std::queue<std::pair<YAML::Node, YAML::Node>> nodesToProcess; | ||
nodesToProcess.emplace(baseYaml, additionalYaml); | ||
|
||
while (!nodesToProcess.empty()) | ||
{ | ||
auto [baseNode, additionalNode] = nodesToProcess.front(); | ||
nodesToProcess.pop(); | ||
|
||
// Traverse each key-value pair in the additionalYaml node. | ||
for (auto it = additionalNode.begin(); it != additionalNode.end(); ++it) | ||
{ | ||
const auto key = it->first.as<std::string>(); | ||
YAML::Node value = it->second; | ||
|
||
if (baseNode[key]) | ||
{ | ||
// Key exists in the baseYaml node. | ||
if (value.IsMap() && baseNode[key].IsMap()) | ||
{ | ||
// Both values are maps: enqueue for further merging. | ||
nodesToProcess.emplace(baseNode[key], value); | ||
} | ||
else if (value.IsSequence() && baseNode[key].IsSequence()) | ||
{ | ||
// Merge sequences while preserving the order. | ||
YAML::Node mergedSequence = YAML::Node(YAML::NodeType::Sequence); | ||
|
||
// Collect elements from 'additionalYaml' sequence to preserve insertion order. | ||
std::vector<std::pair<std::string, YAML::Node>> additionalElements; | ||
for (const YAML::Node& elem : value) | ||
{ | ||
if (elem.IsScalar()) | ||
{ | ||
additionalElements.emplace_back(elem.as<std::string>(), elem); | ||
} | ||
else if (elem.IsMap() && elem.begin() != elem.end()) | ||
{ | ||
additionalElements.emplace_back(elem.begin()->first.as<std::string>(), elem); | ||
} | ||
} | ||
|
||
// Track which keys from 'additionalYaml' sequence are merged. | ||
std::unordered_set<std::string> mergedKeys; | ||
|
||
for (const YAML::Node& elem : baseNode[key]) | ||
{ | ||
std::string elemKey; | ||
|
||
// Extract the key based on the type of element. | ||
if (elem.IsScalar()) | ||
{ | ||
elemKey = elem.as<std::string>(); | ||
} | ||
else if (elem.IsMap() && elem.begin() != elem.end()) | ||
{ | ||
elemKey = elem.begin()->first.as<std::string>(); | ||
} | ||
else | ||
{ | ||
// Skip elements that don't fit the expected types. | ||
mergedSequence.push_back(elem); | ||
continue; | ||
} | ||
|
||
// Common logic for merging elements. | ||
auto additionalItem = | ||
std::find_if(additionalElements.begin(), | ||
additionalElements.end(), | ||
[&elemKey](const auto& pair) { return pair.first == elemKey; }); | ||
if (additionalItem != additionalElements.end()) | ||
{ | ||
mergedSequence.push_back(additionalItem->second); | ||
mergedKeys.insert(additionalItem->first); | ||
} | ||
else | ||
{ | ||
mergedSequence.push_back(elem); | ||
} | ||
} | ||
|
||
// Add remaining elements from 'additionalYaml' sequence in order. | ||
for (const auto& [itemKey, itemNode] : additionalElements) | ||
{ | ||
if (mergedKeys.find(itemKey) == mergedKeys.end()) | ||
{ | ||
mergedSequence.push_back(itemNode); | ||
} | ||
} | ||
|
||
baseNode[key] = mergedSequence; | ||
} | ||
else | ||
{ | ||
// Other cases (scalar, alias, null): overwrite the value. | ||
baseNode[key] = value; | ||
} | ||
} | ||
else | ||
{ | ||
// Key does not exist in the baseYaml node: add it directly. | ||
baseNode[key] = value; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,13 @@ | ||
find_package(GTest CONFIG REQUIRED) | ||
find_package(yaml-cpp CONFIG REQUIRED) | ||
|
||
add_executable(ConfigurationParser_test configuration_parser_test.cpp) | ||
configure_target(ConfigurationParser_test) | ||
target_link_libraries(ConfigurationParser_test PUBLIC ConfigurationParser Config GTest::gtest GTest::gtest_main GTest::gmock GTest::gmock_main Logger) | ||
add_test(NAME ConfigParserTest COMMAND ConfigurationParser_test) | ||
|
||
add_executable(ConfigurationParserUtils_test configuration_parser_utils_test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../src/configuration_parser_utils.cpp) | ||
configure_target(ConfigurationParserUtils_test) | ||
target_include_directories(ConfigurationParserUtils_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include) | ||
target_link_libraries(ConfigurationParserUtils_test PUBLIC GTest::gtest GTest::gtest_main GTest::gmock GTest::gmock_main yaml-cpp::yaml-cpp) | ||
add_test(NAME ConfigParserUtilsTest COMMAND ConfigurationParserUtils_test) |
Oops, something went wrong.