Create version dbus object

Read the version and purpose from the manifest.
Compute the id from the version. Create the image dir,
<IMAGE_UPLOAD_DIR>/<id>/. Create the version object
with the version, purpose, id and image dir path.

Change-Id: I6d2d710fb8eeeda085af8ab116f2dafc720a2ade
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/image_manager.cpp b/image_manager.cpp
index 02bc9a9..235a5d6 100644
--- a/image_manager.cpp
+++ b/image_manager.cpp
@@ -4,11 +4,13 @@
 #include <cstring>
 #include <stdio.h>
 #include <unistd.h>
+#include <algorithm>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <phosphor-logging/log.hpp>
 #include "config.h"
 #include "version.hpp"
+#include "watch.hpp"
 #include "image_manager.hpp"
 
 namespace phosphor
@@ -32,7 +34,7 @@
     }
 };
 
-int processImage(const std::string& tarFilePath)
+int Manager::processImage(const std::string& tarFilePath)
 {
     if (!fs::is_regular_file(tarFilePath))
     {
@@ -95,6 +97,35 @@
         return -1;
     }
 
+    // Get purpose
+    auto purposeString = Version::getValue(manifestPath.string(), "purpose");
+    if (purposeString.empty())
+    {
+        log<level::ERR>("Error unable to read purpose from manifest file");
+        return -1;
+    }
+
+    std::transform(purposeString.begin(), purposeString.end(),
+                   purposeString.begin(), ::tolower);
+
+    auto purpose = Version::VersionPurpose::Unknown;
+    if (purposeString.compare("bmc") == 0)
+    {
+        purpose = Version::VersionPurpose::BMC;
+    }
+    else if (purposeString.compare("host") == 0)
+    {
+        purpose = Version::VersionPurpose::Host;
+    }
+    else if (purposeString.compare("system") == 0)
+    {
+        purpose = Version::VersionPurpose::System;
+    }
+    else if (purposeString.compare("other") == 0)
+    {
+        purpose = Version::VersionPurpose::Other;
+    }
+
     // Compute id
     auto id = Version::getId(version);
 
@@ -109,17 +140,30 @@
     }
 
     // Untar tarball
-    auto rc = unTar(tarFilePath, imageDirPath.string());
+    auto rc = Manager::unTar(tarFilePath, imageDirPath.string());
     if (rc < 0)
     {
         log<level::ERR>("Error occured during untar");
         return -1;
     }
 
+    // Create Version object
+    auto objPath =  std::string{SOFTWARE_OBJPATH} + '/' + id;
+
+    this->versions.insert(std::make_pair(
+                              id,
+                              std::make_unique<Version>(
+                                  this->bus,
+                                  objPath,
+                                  version,
+                                  purpose,
+                                  imageDirPath.string())));
+
     return 0;
 }
 
-int unTar(const std::string& tarFilePath, const std::string& extractDirPath)
+int Manager::unTar(const std::string& tarFilePath,
+                   const std::string& extractDirPath)
 {
     if (tarFilePath.empty())
     {
@@ -160,6 +204,7 @@
 
     return 0;
 }
+
 } // namespace manager
 } // namespace software
 } // namepsace phosphor
diff --git a/image_manager.hpp b/image_manager.hpp
index 49baffe..ac44539 100644
--- a/image_manager.hpp
+++ b/image_manager.hpp
@@ -1,4 +1,5 @@
 #pragma once
+#include "version.hpp"
 
 namespace phosphor
 {
@@ -7,24 +8,48 @@
 namespace manager
 {
 
-/**
- * @brief Verify and untar the tarball. Verify the manifest file.
- *        Create and populate the version and filepath interfaces.
- *
- * @param[in]  tarballFilePath - Tarball path.
- * @param[out] result          - 0 if successful.
+/** @class Manager
+ *  @brief Contains a map of Version dbus objects.
+ *  @details The software image manager class that contains the Version dbus
+ *           objects and their version ids.
  */
-int processImage(const std::string& tarballFilePath);
+class Manager
+{
+    public:
+        /** @brief Constructs Manager Class
+         *
+         * @param[in] bus - The Dbus bus object
+         */
+        Manager(sdbusplus::bus::bus& bus) : bus(bus) {};
 
-/**
- * @brief Untar the tarball.
- *
- * @param[in]  tarballFilePath - Tarball path.
- * @param[in]  extractDirPath  - Dir path to extract tarball ball to.
- * @param[out] result          - 0 if successful.
- */
-int unTar(const std::string& tarballFilePath,
-          const std::string& extractDirPath);
+        /**
+         * @brief Verify and untar the tarball. Verify the manifest file.
+         *        Create and populate the version and filepath interfaces.
+         *
+         * @param[in]  tarballFilePath - Tarball path.
+         * @param[out] result          - 0 if successful.
+         */
+         int processImage(const std::string& tarballFilePath);
+
+    private:
+        /** @brief Persistent map of Version dbus objects and their
+          * version id */
+        std::map<std::string, std::unique_ptr<Version>> versions;
+
+        /** @brief Persistent sdbusplus DBus bus connection. */
+        sdbusplus::bus::bus& bus;
+
+        /**
+         * @brief Untar the tarball.
+         *
+         * @param[in]  tarballFilePath - Tarball path.
+         * @param[in]  extractDirPath  - Dir path to extract tarball ball to.
+         * @param[out] result          - 0 if successful.
+         */
+        static int unTar(const std::string& tarballFilePath,
+                         const std::string& extractDirPath);
+
+};
 
 } // namespace manager
 } // namespace software
diff --git a/image_manager_main.cpp b/image_manager_main.cpp
index 00872e1..d0cac65 100644
--- a/image_manager_main.cpp
+++ b/image_manager_main.cpp
@@ -5,6 +5,7 @@
 #include "config.h"
 #include "bmc_version.hpp"
 #include "watch.hpp"
+#include "image_manager.hpp"
 
 int main(int argc, char* argv[])
 {
@@ -21,7 +22,12 @@
 
     try
     {
-        phosphor::software::manager::Watch watch(loop);
+        phosphor::software::manager::Manager imageManager(bus);
+        phosphor::software::manager::Watch watch(loop,
+                std::bind(
+                    std::mem_fn(
+                        &phosphor::software::manager::Manager::processImage),
+                    &imageManager, std::placeholders::_1));
         bus.attach_event(loop, SD_EVENT_PRIORITY_NORMAL);
         sd_event_loop(loop);
     }
diff --git a/watch.cpp b/watch.cpp
index da1f967..9921bbd 100644
--- a/watch.cpp
+++ b/watch.cpp
@@ -21,7 +21,9 @@
 using namespace std::string_literals;
 namespace fs = std::experimental::filesystem;
 
-Watch::Watch(sd_event* loop)
+Watch::Watch(sd_event* loop,
+             std::function<int(std::string&)> imageCallback) : imageCallback(
+                     imageCallback)
 {
     // Check if IMAGE DIR exists.
     fs::path imgDirPath(IMG_UPLOAD_DIR);
@@ -100,12 +102,12 @@
         auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
         if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
         {
-            auto rc = processImage(std::string{IMG_UPLOAD_DIR} +
-                                   '/' + event->name);
+            auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
+            auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
             if (rc < 0)
             {
                 log<level::ERR>("Error processing image",
-                                entry("IMAGE=%s", std::string{event->name}));
+                                entry("IMAGE=%s", tarballPath));
             }
 
         }
diff --git a/watch.hpp b/watch.hpp
index c125ef2..b118d59 100644
--- a/watch.hpp
+++ b/watch.hpp
@@ -22,8 +22,11 @@
         /** @brief ctor - hook inotify watch with sd-event
          *
          *  @param[in] loop - sd-event object
+         *  @param[in] imageCallback - The callback function for processing
+         *                             the image
          */
-        Watch(sd_event* loop);
+        Watch(sd_event* loop,
+              std::function<int(std::string&)> imageCallback);
 
         Watch(const Watch&) = delete;
         Watch& operator=(const Watch&) = delete;
@@ -53,6 +56,9 @@
 
         /** @brief inotify file descriptor */
         int fd = -1;
+
+        /** @brief The callback function for processing the image. */
+        std::function<int(std::string&)> imageCallback;
 };
 
 } // namespace manager