Prime the Inventory VPD objects

At the time of collecting the system vpd, prime those non system vpd
inventory objects by populating only certain properites of the objects
(like - Location code, Type interface and the inventory object).

Test:
Tested on simics by adding a missing fru in inventory json
and introspecting it to get the primed version of the object.

Output:

root@rainier:/tmp# busctl introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dasd_card_pyramid0
NAME                                             TYPE      SIGNATURE RESULT/VALUE           FLAGS
com.ibm.ipzvpd.Location                          interface -         -                      -
.LocationCode                                    property  s         "U78DA.ND1.1234567-P1" emits-change writable
org.freedesktop.DBus.Introspectable              interface -         -                      -
.Introspect                                      method    -         s                      -
org.freedesktop.DBus.Peer                        interface -         -                      -
.GetMachineId                                    method    -         s                      -
.Ping                                            method    -         -                      -
org.freedesktop.DBus.Properties                  interface -         -                      -
.Get                                             method    ss        v                      -
.GetAll                                          method    s         a{sv}                  -
.Set                                             method    ssv       -                      -
.PropertiesChanged                               signal    sa{sv}as  -                      -
xyz.openbmc_project.Inventory.Item.DiskBackplane interface -         -                      -

Tested in conjunction with this commit
<https://gerrit.openbmc-project.xyz/c/openbmc/meta-ibm/+/31821>

Change-Id: I4bf44e47b7cd1206555c42de43002c6aa8424517
Signed-off-by: Priyanga Ramasamy <priyanga24@in.ibm.com>
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index 4100d83..4c3aba4 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -85,7 +85,6 @@
     }
     return expanded;
 }
-
 /**
  * @brief Populate FRU specific interfaces.
  *
@@ -200,11 +199,74 @@
 }
 
 /**
- * @brief Populate Dbus.
+ * @brief Prime the Inventory
+ * Prime the inventory by populating only the location code,
+ * type interface and the inventory object for the frus
+ * which are not system vpd fru.
  *
+ * @param[in] jsObject - Reference to vpd inventory json object
+ * @param[in] vpdMap -  Reference to the parsed vpd map
+ *
+ * @returns Map of items in extraInterface.
+ */
+template <typename T>
+inventory::ObjectMap primeInventory(const nlohmann::json& jsObject,
+                                    const T& vpdMap)
+{
+    inventory::ObjectMap objects;
+
+    for (auto& itemFRUS : jsObject["frus"].items())
+    {
+        for (auto& itemEEPROM : itemFRUS.value())
+        {
+            inventory::InterfaceMap interfaces;
+            auto isSystemVpd = itemEEPROM.value("isSystemVpd", false);
+            inventory::Object object(itemEEPROM.at("inventoryPath"));
+
+            if (!isSystemVpd && !itemEEPROM.value("noprime", false))
+            {
+                if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end())
+                {
+                    for (const auto& eI : itemEEPROM["extraInterfaces"].items())
+                    {
+                        inventory::PropertyMap props;
+                        if (eI.key() ==
+                            openpower::vpd::constants::LOCATION_CODE_INF)
+                        {
+                            if constexpr (std::is_same<T, Parsed>::value)
+                            {
+                                for (auto& lC : eI.value().items())
+                                {
+                                    auto propVal = expandLocationCode(
+                                        lC.value().get<string>(), vpdMap, true);
+
+                                    props.emplace(move(lC.key()),
+                                                  move(propVal));
+                                    interfaces.emplace(move(eI.key()),
+                                                       move(props));
+                                }
+                            }
+                        }
+                        else if (eI.key().find("Inventory.Item.") !=
+                                 string::npos)
+                        {
+                            interfaces.emplace(move(eI.key()), move(props));
+                        }
+                    }
+                }
+                objects.emplace(move(object), move(interfaces));
+            }
+        }
+    }
+    return objects;
+}
+
+/**
+ * @brief Populate Dbus.
  * This method invokes all the populateInterface functions
  * and notifies PIM about dbus object.
- * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the input.
+ * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the
+ * input.
  * @param[in] js - Inventory json object
  * @param[in] filePath - Path of the vpd file
  * @param[in] preIntrStr - Interface string
@@ -217,11 +279,12 @@
     inventory::ObjectMap objects;
     inventory::PropertyMap prop;
 
+    bool isSystemVpd;
     for (const auto& item : js["frus"][filePath])
     {
         const auto& objectPath = item["inventoryPath"];
         sdbusplus::message::object_path object(objectPath);
-        auto isSystemVpd = item.value("isSystemVpd", false);
+        isSystemVpd = item.value("isSystemVpd", false);
         // Populate the VPD keywords and the common interfaces only if we
         // are asked to inherit that data from the VPD, else only add the
         // extraInterfaces.
@@ -229,8 +292,9 @@
         {
             if constexpr (std::is_same<T, Parsed>::value)
             {
-                // Each record in the VPD becomes an interface and all keyword
-                // within the record are properties under that interface.
+                // Each record in the VPD becomes an interface and all
+                // keyword within the record are properties under that
+                // interface.
                 for (const auto& record : vpdMap)
                 {
                     populateFruSpecificInterfaces(
@@ -269,7 +333,8 @@
         }
 
         // Populate interfaces and properties that are common to every FRU
-        // and additional interface that might be defined on a per-FRU basis.
+        // and additional interface that might be defined on a per-FRU
+        // basis.
         if (item.find("extraInterfaces") != item.end())
         {
             populateInterfaces(item["extraInterfaces"], interfaces, vpdMap,
@@ -278,6 +343,12 @@
         objects.emplace(move(object), move(interfaces));
     }
 
+    if (isSystemVpd)
+    {
+        inventory::ObjectMap primeObject = primeInventory(js, vpdMap);
+        objects.insert(primeObject.begin(), primeObject.end());
+    }
+
     // Notify PIM
     inventory::callPIM(move(objects));
 }