Add support for Inventory.Decorator.Compatible
This adds support for the compatibility strings interface described in
https://github.com/openbmc/phosphor-dbus-interfaces/tree/master/yaml/xyz/openbmc_project/Software#compatibility.
The Version objects will now be created with the Inventory.Decorator.Compatible
interface with the compatibility names coming from the MANIFEST file.
e.g.
version=1.2.3
MachineName=foo
purpose=Other
ExtendedVersion=a.b.c
CompatibleName=foo.bar
CompatibleName=baz.bim
Tested:
$ busctl get-property xyz.openbmc_project.Software.Version \
/xyz/openbmc_project/software/517751da \
xyz.openbmc_project.Inventory.Decorator.Compatible Names
as 2 "foo.bar" "baz.bim"
Signed-off-by: Justin Ledford <justinledford@google.com>
Change-Id: I9ee36af2d3d1494d533a3b09c466a250c4fe786b
diff --git a/image_manager.cpp b/image_manager.cpp
index 604b952..b02abd3 100644
--- a/image_manager.cpp
+++ b/image_manager.cpp
@@ -188,6 +188,10 @@
std::string extendedVersion =
Version::getValue(manifestPath.string(), "ExtendedVersion");
+ // Get CompatibleNames
+ std::vector<std::string> compatibleNames =
+ Version::getRepeatedValues(manifestPath.string(), "CompatibleName");
+
// Compute id
auto salt = std::to_string(randomGen());
auto id = Version::getId(version + salt);
@@ -213,7 +217,7 @@
// Create Version object
auto versionPtr = std::make_unique<Version>(
bus, objPath, version, purpose, extendedVersion,
- imageDirPath.string(),
+ imageDirPath.string(), compatibleNames,
std::bind(&Manager::erase, this, std::placeholders::_1), id);
versionPtr->deleteObject =
std::make_unique<phosphor::software::manager::Delete>(bus, objPath,
diff --git a/item_updater.cpp b/item_updater.cpp
index cfe0ae5..c8fda76 100644
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -49,11 +49,14 @@
auto purpose = VersionPurpose::Unknown;
std::string extendedVersion;
std::string version;
- std::map<std::string, std::map<std::string, std::variant<std::string>>>
+ std::map<std::string,
+ std::map<std::string,
+ std::variant<std::string, std::vector<std::string>>>>
interfaces;
msg.read(objPath, interfaces);
std::string path(std::move(objPath));
std::string filePath;
+ std::vector<std::string> compatibleNames;
for (const auto& intf : interfaces)
{
@@ -100,6 +103,17 @@
}
}
}
+ else if (intf.first == COMPATIBLE_IFACE)
+ {
+ for (const auto& property : intf.second)
+ {
+ if (property.first == "Names")
+ {
+ compatibleNames =
+ std::get<std::vector<std::string>>(property.second);
+ }
+ }
+ }
}
if (version.empty() || filePath.empty() ||
purpose == VersionPurpose::Unknown)
@@ -140,6 +154,7 @@
auto versionPtr = std::make_unique<VersionClass>(
bus, path, version, purpose, extendedVersion, filePath,
+ compatibleNames,
std::bind(&ItemUpdater::erase, this, std::placeholders::_1),
versionId);
versionPtr->deleteObject =
@@ -284,6 +299,7 @@
// Create Version instance for this version.
auto versionPtr = std::make_unique<VersionClass>(
bus, path, version, purpose, extendedVersion, flashId,
+ std::vector<std::string>(),
std::bind(&ItemUpdater::erase, this, std::placeholders::_1),
id);
if (functional)
@@ -843,6 +859,7 @@
};
biosVersion = std::make_unique<VersionClass>(
bus, path, version, VersionPurpose::Host, "", "",
+ std::vector<std::string>(),
std::bind(dummyErase, std::placeholders::_1), "");
biosVersion->deleteObject =
std::make_unique<phosphor::software::manager::Delete>(bus, path,
diff --git a/meson.build b/meson.build
index c3ed12c..68954bc 100644
--- a/meson.build
+++ b/meson.build
@@ -40,6 +40,7 @@
conf.set_quoted('VERSION_BUSNAME', 'xyz.openbmc_project.Software.Version')
conf.set_quoted('VERSION_IFACE', 'xyz.openbmc_project.Software.Version')
conf.set_quoted('EXTENDED_VERSION_IFACE', 'xyz.openbmc_project.Software.ExtendedVersion')
+conf.set_quoted('COMPATIBLE_IFACE', 'xyz.openbmc_project.Inventory.Decorator.Compatible')
# Names of the forward and reverse associations
conf.set_quoted('ACTIVATION_FWD_ASSOCIATION', 'inventory')
diff --git a/test/utest.cpp b/test/utest.cpp
index 1c32b1a..03dbe26 100644
--- a/test/utest.cpp
+++ b/test/utest.cpp
@@ -58,6 +58,25 @@
EXPECT_EQ(Version::getValue(manifestFilePath, "purpose"), purpose);
}
+TEST_F(VersionTest, TestGetRepeatedValue)
+{
+ auto manifestFilePath = _directory + "/" + "MANIFEST";
+ const std::vector<std::string> names = {"foo.bar", "baz.bim"};
+
+ std::ofstream file;
+ file.open(manifestFilePath, std::ofstream::out);
+ ASSERT_TRUE(file.is_open());
+
+ for (const auto& name : names)
+ {
+ file << "CompatibleName=" << name << "\n";
+ }
+ file.close();
+
+ EXPECT_EQ(Version::getRepeatedValues(manifestFilePath, "CompatibleName"),
+ names);
+}
+
TEST_F(VersionTest, TestGetValueWithCRLF)
{
auto manifestFilePath = _directory + "/" + "MANIFEST";
diff --git a/version.cpp b/version.cpp
index 250c221..f7fbd2b 100644
--- a/version.cpp
+++ b/version.cpp
@@ -30,6 +30,23 @@
std::string Version::getValue(const std::string& manifestFilePath,
std::string key)
{
+ std::vector<std::string> values = getRepeatedValues(manifestFilePath, key);
+ if (values.empty())
+ {
+ return std::string{};
+ }
+ if (values.size() > 1)
+ {
+ error("Multiple values found in MANIFEST file for key: {KEY}", "KEY",
+ key);
+ }
+ return values.at(0);
+}
+
+std::vector<std::string>
+ Version::getRepeatedValues(const std::string& manifestFilePath,
+ std::string key)
+{
key = key + "=";
auto keySize = key.length();
@@ -41,11 +58,10 @@
Argument::ARGUMENT_VALUE(manifestFilePath.c_str()));
}
- std::string value{};
+ std::vector<std::string> values{};
std::ifstream efile;
std::string line;
- efile.exceptions(std::ifstream::failbit | std::ifstream::badbit |
- std::ifstream::eofbit);
+ efile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
// Too many GCC bugs (53984, 66145) to do this the right way...
try
@@ -61,19 +77,26 @@
}
if (line.compare(0, keySize, key) == 0)
{
- value = line.substr(keySize);
- break;
+ values.push_back(line.substr(keySize));
}
}
efile.close();
}
catch (const std::exception& e)
{
- error("Error occurred when reading MANIFEST file: {ERROR}", "KEY", key,
- "ERROR", e);
+ if (!efile.eof())
+ {
+ error("Error occurred when reading MANIFEST file: {ERROR}", "KEY",
+ key, "ERROR", e);
+ }
}
- return value;
+ if (values.empty())
+ {
+ error("No values found in MANIFEST file for key: {KEY}", "KEY", key);
+ }
+
+ return values;
}
using EVP_MD_CTX_Ptr =
diff --git a/version.hpp b/version.hpp
index b6269e0..b6f9172 100644
--- a/version.hpp
+++ b/version.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "xyz/openbmc_project/Common/FilePath/server.hpp"
+#include "xyz/openbmc_project/Inventory/Decorator/Compatible/server.hpp"
#include "xyz/openbmc_project/Object/Delete/server.hpp"
#include "xyz/openbmc_project/Software/ExtendedVersion/server.hpp"
#include "xyz/openbmc_project/Software/Version/server.hpp"
@@ -9,6 +10,7 @@
#include <functional>
#include <string>
+#include <vector>
namespace phosphor
{
@@ -22,7 +24,8 @@
using VersionInherit = sdbusplus::server::object::object<
sdbusplus::xyz::openbmc_project::Software::server::ExtendedVersion,
sdbusplus::xyz::openbmc_project::Software::server::Version,
- sdbusplus::xyz::openbmc_project::Common::server::FilePath>;
+ sdbusplus::xyz::openbmc_project::Common::server::FilePath,
+ sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::Compatible>;
using DeleteInherit = sdbusplus::server::object::object<
sdbusplus::xyz::openbmc_project::Object::server::Delete>;
@@ -68,18 +71,20 @@
public:
/** @brief Constructs Version Software Manager
*
- * @param[in] bus - The D-Bus bus object
- * @param[in] objPath - The D-Bus object path
- * @param[in] versionString - The version string
- * @param[in] versionPurpose - The version purpose
- * @param[in] extVersion - The extended version
- * @param[in] filePath - The image filesystem path
- * @param[in] callback - The eraseFunc callback
+ * @param[in] bus - The D-Bus bus object
+ * @param[in] objPath - The D-Bus object path
+ * @param[in] versionString - The version string
+ * @param[in] versionPurpose - The version purpose
+ * @param[in] extVersion - The extended version
+ * @param[in] filePath - The image filesystem path
+ * @param[in] compatibleNames - The device compatibility names
+ * @param[in] callback - The eraseFunc callback
*/
Version(sdbusplus::bus::bus& bus, const std::string& objPath,
const std::string& versionString, VersionPurpose versionPurpose,
const std::string& extVersion, const std::string& filePath,
- eraseFunc callback, const std::string& id) :
+ const std::vector<std::string>& compatibleNames, eraseFunc callback,
+ const std::string& id) :
VersionInherit(bus, (objPath).c_str(), true),
eraseCallback(callback), id(id), versionStr(versionString)
{
@@ -88,6 +93,7 @@
purpose(versionPurpose);
version(versionString);
path(filePath);
+ names(compatibleNames);
// Emit deferred signal.
emit_object_added();
}
@@ -101,6 +107,14 @@
std::string key);
/**
+ * @brief Read the manifest file to get the values of the repeated key.
+ *
+ * @return The values of the repeated key.
+ **/
+ static std::vector<std::string>
+ getRepeatedValues(const std::string& manifestFilePath, std::string key);
+
+ /**
* @brief Calculate the version id from the version string.
*
* @details The version id is a unique 8 hexadecimal digit id