Add basic math support to template char replace
This adds basic math support, so we can modify entities
based on found properties.
Tested: Modified PSU config in follow-on commit, all sensors
still available.
Change-Id: I07286cf17b04b7e3acdbfdfa43454f17338bf56b
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/include/EntityManager.hpp b/include/EntityManager.hpp
index 74ba827..548cc5f 100644
--- a/include/EntityManager.hpp
+++ b/include/EntityManager.hpp
@@ -47,7 +47,15 @@
}
if (findSn != findAsset->end())
{
- sn = findSn->get<std::string>();
+ const std::string* getSn = findSn->get_ptr<const std::string*>();
+ if (getSn != nullptr)
+ {
+ sn = *getSn;
+ }
+ else
+ {
+ sn = findSn->dump();
+ }
}
}
@@ -81,7 +89,15 @@
}
if (findSn != findAsset->end())
{
- sn = findSn->get<std::string>();
+ const std::string* getSn = findSn->get_ptr<const std::string*>();
+ if (getSn != nullptr)
+ {
+ sn = *getSn;
+ }
+ else
+ {
+ sn = findSn->dump();
+ }
}
}
@@ -89,4 +105,13 @@
"REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.InventoryRemoved",
"REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
type.c_str(), sn.c_str(), NULL);
-}
\ No newline at end of file
+}
+
+enum class TemplateOperation
+{
+ addition,
+ division,
+ multiplication,
+ subtraction,
+ modulo,
+};
\ No newline at end of file
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index da940b3..3704f84 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -20,11 +20,14 @@
#include <Utils.hpp>
#include <VariantVisitors.hpp>
#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/split.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/range/iterator_range.hpp>
#include <filesystem>
#include <fstream>
#include <iostream>
@@ -40,7 +43,7 @@
constexpr const char* lastConfiguration = "/tmp/configuration/last.json";
constexpr const char* currentConfiguration = "/var/configuration/system.json";
constexpr const char* globalSchema = "global.json";
-constexpr const char* TEMPLATE_CHAR = "$";
+constexpr const char* templateChar = "$";
constexpr const int32_t MAX_MAPPER_DEPTH = 0;
constexpr const bool DEBUG = false;
@@ -304,9 +307,7 @@
}
if (deviceMatches)
{
- devices.emplace_back(
- boost::container::flat_map<std::string, BasicVariantType>(
- device));
+ devices.emplace_back(device);
foundMatch = true;
deviceMatches = false; // for next iteration
}
@@ -1145,15 +1146,148 @@
return;
}
- boost::replace_all(*strPtr, "$index", std::to_string(foundDeviceIdx));
+ boost::replace_all(*strPtr, std::string(templateChar) + "index",
+ std::to_string(foundDeviceIdx));
for (auto& foundDevicePair : foundDevice)
{
- std::string templateName = "$" + foundDevicePair.first;
- if (boost::iequals(*strPtr, templateName))
+ std::string templateName = templateChar + foundDevicePair.first;
+ boost::iterator_range<std::string::const_iterator> find =
+ boost::ifind_first(*strPtr, templateName);
+ if (find)
{
- std::visit([&](auto&& val) { keyPair.value() = val; },
- foundDevicePair.second);
+ size_t start = find.begin() - strPtr->begin();
+ // check for additional operations
+ if (find.end() != strPtr->end())
+ {
+ // save the prefix
+ std::string prefix = strPtr->substr(0, start);
+
+ // operate on the rest (+1 for trailing space)
+ std::string end =
+ strPtr->substr(start + templateName.size() + 1);
+
+ std::vector<std::string> split;
+ boost::split(split, end, boost::is_any_of(" "));
+
+ // need at least 1 operation and number
+ if (split.size() < 2)
+ {
+ std::cerr << "Syntax error on template replacement of "
+ << *strPtr << "\n";
+ for (const std::string& data : split)
+ {
+ std::cerr << data << " ";
+ }
+ std::cerr << "\n";
+ continue;
+ }
+
+ // we assume that the replacement is a number, because we can
+ // only do math on numbers.. we might concatenate strings in the
+ // future, but thats later
+ int number =
+ std::visit(VariantToIntVisitor(), foundDevicePair.second);
+
+ bool isOperator = true;
+ TemplateOperation next = TemplateOperation::addition;
+
+ auto it = split.begin();
+
+ for (; it != split.end(); it++)
+ {
+ if (isOperator)
+ {
+ if (*it == "+")
+ {
+ next = TemplateOperation::addition;
+ }
+ else if (*it == "-")
+ {
+ next = TemplateOperation::subtraction;
+ }
+ else if (*it == "*")
+ {
+ next = TemplateOperation::multiplication;
+ }
+ else if (*it == R"(%)")
+ {
+ next = TemplateOperation::modulo;
+ }
+ else if (*it == R"(/)")
+ {
+ next = TemplateOperation::division;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ int constant = 0;
+ try
+ {
+ constant = std::stoi(*it);
+ }
+ catch (std::invalid_argument&)
+ {
+ std::cerr
+ << "Parameter not supported for templates "
+ << *it << "\n";
+ continue;
+ }
+ switch (next)
+ {
+ case TemplateOperation::addition:
+ {
+ number += constant;
+ break;
+ }
+ case TemplateOperation::subtraction:
+ {
+ number -= constant;
+ break;
+ }
+ case TemplateOperation::multiplication:
+ {
+ number *= constant;
+ break;
+ }
+ case TemplateOperation::division:
+ {
+ number /= constant;
+ break;
+ }
+ case TemplateOperation::modulo:
+ {
+ number = number % constant;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ isOperator = !isOperator;
+ }
+ std::string result = prefix + std::to_string(number);
+
+ if (it != split.end())
+ {
+ for (; it != split.end(); it++)
+ {
+ result += " " + *it;
+ }
+ }
+ keyPair.value() = result;
+ }
+ else
+ {
+ std::visit([&](auto&& val) { keyPair.value() = val; },
+ foundDevicePair.second);
+ }
+
// We probably just invalidated the pointer above, so set it to null
strPtr = nullptr;
break;
@@ -1189,6 +1323,18 @@
{
}
}
+ // non-hex numbers
+ else
+ {
+ try
+ {
+ uint64_t temp = boost::lexical_cast<uint64_t>(*strPtr);
+ keyPair.value() = temp;
+ }
+ catch (boost::bad_lexical_cast&)
+ {
+ }
+ }
}
// reads json files out of the filesystem
@@ -1327,10 +1473,9 @@
PASSED_PROBES.push_back(probeName);
size_t foundDeviceIdx = 0;
- nlohmann::json record = *recordPtr;
-
for (auto& foundDevice : foundDevices)
{
+ nlohmann::json record = *recordPtr;
std::string recordName;
size_t hash = 0;
if (foundDevice)