pseq: Find config file using new compatible intf

Add support for finding the JSON configuration file using a list of
compatible names from the new
xyz.openbmc_project.Inventory.Decorator.Compatible D-Bus interface.

Change-Id: Ic24bafd1d77413015aa8eac7b312dbd604a10995
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
diff --git a/phosphor-power-sequencer/src/config_file_parser.cpp b/phosphor-power-sequencer/src/config_file_parser.cpp
index fe9c661..83754b1 100644
--- a/phosphor-power-sequencer/src/config_file_parser.cpp
+++ b/phosphor-power-sequencer/src/config_file_parser.cpp
@@ -23,10 +23,51 @@
 #include <optional>
 
 using json = nlohmann::json;
+namespace fs = std::filesystem;
 
 namespace phosphor::power::sequencer::config_file_parser
 {
 
+const std::filesystem::path standardConfigFileDirectory{
+    "/usr/share/phosphor-power-sequencer"};
+
+std::filesystem::path
+    find(const std::vector<std::string>& compatibleSystemTypes,
+         const std::filesystem::path& configFileDir)
+{
+    fs::path pathName, possiblePath;
+    std::string fileName;
+
+    for (const std::string& systemType : compatibleSystemTypes)
+    {
+        // Look for file name that is entire system type + ".json"
+        // Example: com.acme.Hardware.Chassis.Model.MegaServer.json
+        fileName = systemType + ".json";
+        possiblePath = configFileDir / fileName;
+        if (fs::is_regular_file(possiblePath))
+        {
+            pathName = possiblePath;
+            break;
+        }
+
+        // Look for file name that is last node of system type + ".json"
+        // Example: MegaServer.json
+        std::string::size_type pos = systemType.rfind('.');
+        if ((pos != std::string::npos) && ((systemType.size() - pos) > 1))
+        {
+            fileName = systemType.substr(pos + 1) + ".json";
+            possiblePath = configFileDir / fileName;
+            if (fs::is_regular_file(possiblePath))
+            {
+                pathName = possiblePath;
+                break;
+            }
+        }
+    }
+
+    return pathName;
+}
+
 std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName)
 {
     try
diff --git a/phosphor-power-sequencer/src/config_file_parser.hpp b/phosphor-power-sequencer/src/config_file_parser.hpp
index dbd41d7..77d9650 100644
--- a/phosphor-power-sequencer/src/config_file_parser.hpp
+++ b/phosphor-power-sequencer/src/config_file_parser.hpp
@@ -30,6 +30,36 @@
 {
 
 /**
+ * Standard JSON configuration file directory on the BMC.
+ */
+extern const std::filesystem::path standardConfigFileDirectory;
+
+/**
+ * Finds the JSON configuration file for the current system based on the
+ * specified compatible system types.
+ *
+ * This is required when a single BMC firmware image supports multiple system
+ * types and some system types require different configuration files.
+ *
+ * The compatible system types must be ordered from most to least specific.
+ * Example:
+ *   - com.acme.Hardware.Chassis.Model.MegaServer4CPU
+ *   - com.acme.Hardware.Chassis.Model.MegaServer
+ *   - com.acme.Hardware.Chassis.Model.Server
+ *
+ * Throws an exception if an error occurs.
+ *
+ * @param compatibleSystemTypes compatible system types for the current system
+ *                              ordered from most to least specific
+ * @param configFileDir directory containing configuration files
+ * @return path to the JSON configuration file, or an empty path if none was
+ *         found
+ */
+std::filesystem::path find(
+    const std::vector<std::string>& compatibleSystemTypes,
+    const std::filesystem::path& configFileDir = standardConfigFileDirectory);
+
+/**
  * Parses the specified JSON configuration file.
  *
  * Returns the corresponding C++ Rail objects.