Refactor dependency checker 16/238016/7
authorIlho Kim <ilho159.kim@samsung.com>
Mon, 6 Jul 2020 07:20:23 +0000 (16:20 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Fri, 24 Jul 2020 04:07:54 +0000 (13:07 +0900)
Change-Id: Iff4e81c95e10c5ebb6df5e4991d4bf7e16adbe85
Signed-off-by: Ilho Kim <ilho159.kim@samsung.com>
src/common/dependency_checker.cc
src/common/dependency_checker.h
src/common/installer_runner.cc

index 43b8b7aee22b1028e6bb2264f50ce3b66073d240..a56a72f1f339f390522af8e50c3a39eea1f0a51c 100644 (file)
@@ -17,6 +17,7 @@
 #include <memory>
 #include <tuple>
 #include <utility>
+#include <vector>
 
 #include <boost/filesystem/path.hpp>
 
@@ -35,9 +36,12 @@ const char kRequiredDependencyType[] = "requires";
 
 namespace common_installer {
 
-void DependencyChecker::AddEdge(const std::string& from,
-                                const std::string& to) {
-  dep_graph_[from].push_back(to);
+static bool InvalidDependencyError(const std::string& from,
+    const std::string& to, const std::string& required_version) {
+  LOG(ERROR) << "Dependency [" << from << "] -> [" << to
+      << (required_version.empty() ? "" : "(>=" + required_version + ")")
+      << "] is not met";
+  return false;
 }
 
 bool DependencyChecker::AddInstaller(InstallerPtr installer) {
@@ -60,57 +64,106 @@ bool DependencyChecker::AddInstaller(InstallerPtr installer) {
   return true;
 }
 
-bool DependencyChecker::CheckInstallPkgDependencyInfo() {
-  for (const DependencyInfo& dep_info : dep_info_) {
-    std::string from = std::get<0>(dep_info);
-    std::string to = std::get<1>(dep_info);
-    utils::VersionNumber req_version(std::get<3>(dep_info));
-    utils::VersionNumber actual_pkg_version("");
+std::list<InstallerPtr> DependencyChecker::GetSortedAppInstallers() {
+  std::list<InstallerPtr> result;
+  if (!CheckMeetDependency())
+    return {};
+  if (!TopologicalSort(&result))
+    return {};
+
+  return result;
+}
 
-    if (pkg_version_.count(to)) {
-      actual_pkg_version = utils::VersionNumber(pkg_version_[to]);
+bool DependencyChecker::CheckMeetDependency() {
+  if (!CheckInstallPkg())
+    return false;
+  if (!CheckUninstallPkg())
+    return false;
+
+  return true;
+}
+
+bool DependencyChecker::CheckRequires(const std::string& pkgid) {
+  for (const auto& dep_info : dep_graph_[pkgid]) {
+    std::string require_pkgid = dep_info.first;
+    std::string require_version = dep_info.second;
+    std::string actual_pkg_version;
+    if (install_pkgs_.count(require_pkgid)) {
+      actual_pkg_version = install_pkgs_[require_pkgid];
     } else {
-      PkgQueryInterface pkg_query(to, uid_, true);
-      if (!pkg_query.IsValid()) {
-        LOG(ERROR) << "dependency [" << from << "] -> [" << to
-            << "] not met [" << to << "] package is not exist";
-        return false;
-      }
-      actual_pkg_version = utils::VersionNumber(pkg_query.Version());
+      PkgQueryInterface pkg_query(require_pkgid, pkgmgr_->GetUid());
+      if (!pkg_query.IsValid())
+        return InvalidDependencyError(pkgid, require_pkgid, require_version);
+      actual_pkg_version = pkg_query.Version();
     }
 
-    if (req_version.ToString().empty())
+    if (utils::VersionNumber(actual_pkg_version).Compare(
+        utils::VersionNumber(require_version)) < 0)
+      return InvalidDependencyError(pkgid, require_pkgid, require_version);
+  }
+  return true;
+}
+
+bool DependencyChecker::CheckRequiredBy(const std::string& pkgid,
+    const std::string& pkg_version) {
+  PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
+  if (!pkg_query.IsValid())
+    return true;
+
+  std::vector<DependencyInfo> dep_info;
+  if (!pkg_query.PackagesDependsOn(&dep_info)) {
+    LOG(ERROR) << "Failed to get depends on information of package";
+    return false;
+  }
+  for (const auto& info : dep_info) {
+    std::string from = std::get<0>(info);
+    std::string to = std::get<1>(info);
+    std::string type = std::get<2>(info);
+    std::string dependent_version = std::get<3>(info);
+
+    if (to != pkgid || type != kRequiredDependencyType
+        || dependent_version.empty() || install_pkgs_.count(from))
       continue;
 
-    if (actual_pkg_version.Compare(req_version) < 0) {
-      LOG(ERROR) << "Same or higher version (" << req_version.ToString()
-                 << ") of " << to
-                 << " is required but current version of installed package is: "
-                 << actual_pkg_version.ToString();
-      return false;
-    }
+    if (utils::VersionNumber(pkg_version).Compare(
+        utils::VersionNumber(dependent_version)) < 0)
+      return InvalidDependencyError(from, to, dependent_version);
   }
   return true;
 }
 
-bool DependencyChecker::CheckUninstallPkgDependencyInfo() {
-  for (const DependencyInfo& dep_info : dep_info_) {
-    std::string from = std::get<0>(dep_info);
-    std::string to = std::get<1>(dep_info);
-    if (uninstall_pkgs_.count(to) && !uninstall_pkgs_.count(from)) {
-      LOG(ERROR) << "Pkg[" << from << "] requires Pkg[" << to << "]";
+bool DependencyChecker::CheckInstallPkg() {
+  for (const auto& install_pkg : install_pkgs_) {
+    std::string pkgid = install_pkg.first;
+    std::string pkg_version = install_pkg.second;
+    if (!CheckRequires(pkgid))
+      return false;
+    if (!CheckRequiredBy(pkgid, pkg_version))
       return false;
-    }
   }
   return true;
 }
 
-bool DependencyChecker::CheckMeetDependency() {
-  if (!CheckInstallPkgDependencyInfo())
-    return false;
-  if (!CheckUninstallPkgDependencyInfo())
-    return false;
-
+bool DependencyChecker::CheckUninstallPkg() {
+  for (const auto& pkgid : uninstall_pkgs_) {
+    PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
+    std::vector<DependencyInfo> dep_info;
+    if (!pkg_query.PackagesDependsOn(&dep_info)) {
+      LOG(ERROR) << "Failed to get depends on information of package";
+      return false;
+    }
+    for (const auto& info : dep_info) {
+      std::string from = std::get<0>(info);
+      std::string to = std::get<1>(info);
+      std::string type = std::get<2>(info);
+      std::string dependent_version = std::get<3>(info);
+
+      if (to != pkgid || type != kRequiredDependencyType)
+        continue;
+      if (uninstall_pkgs_.count(from) == 0)
+        return InvalidDependencyError(from, to, dependent_version);
+    }
+  }
   return true;
 }
 
@@ -125,15 +178,18 @@ bool DependencyChecker::DFS(const std::string& node,
     }
   }
   visited_.emplace(node);
-  bool ret = true;
-  for (const std::string& next_node : dep_graph_[node])
-    ret &= DFS(next_node, result);
+
+  for (const auto& next_node : dep_graph_[node]) {
+    std::string pkgid = next_node.first;
+    if (!DFS(pkgid, result))
+      return false;
+  }
 
   if (installers_.count(node))
     result->emplace_back(std::move(installers_[node]));
 
   finished_.emplace(node);
-  return ret;
+  return true;
 }
 
 bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
@@ -149,7 +205,6 @@ bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
   std::string pkgid = archive_info->pkgid();
   std::string version = archive_info->version();
   std::vector<Dependency> dependencies = archive_info->dependencies();
-  std::list<DependencyInfo> pkg_dep_info;
 
   for (const Dependency& dep : dependencies) {
     std::string dep_pkg = std::get<0>(dep);
@@ -159,11 +214,10 @@ bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
     if (type != kRequiredDependencyType)
       continue;
 
-    pkg_dep_info.emplace_back(pkgid, dep_pkg, type, required_version);
+    dep_graph_[pkgid].emplace(dep_pkg, required_version);
   }
 
-  pkg_version_[pkgid] = version;
-  dep_info_.splice(dep_info_.end(), pkg_dep_info);
+  install_pkgs_[pkgid] = version;
   installers_.emplace(pkgid, std::move(installer));
   request_pkgid_.emplace_back(pkgid);
 
@@ -172,13 +226,12 @@ bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
 
 bool DependencyChecker::GetDepInfoFromDB(InstallerPtr installer) {
   std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
-  PkgQueryInterface pkg_query(pkgid, uid_, true);
+  PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
   std::vector<DependencyInfo> dep_info;
   if (!pkg_query.PackagesDependsOn(&dep_info)) {
     LOG(ERROR) << "get packages depens on fail";
     return false;
   }
-  std::list<DependencyInfo> pkg_dep_info;
 
   for (const auto& info : dep_info) {
     std::string from = std::get<0>(info);
@@ -189,11 +242,10 @@ bool DependencyChecker::GetDepInfoFromDB(InstallerPtr installer) {
     if (type != kRequiredDependencyType)
       continue;
 
-    pkg_dep_info.emplace_back(from, to, type, version);
+    dep_graph_[from].emplace(to, version);
   }
 
   uninstall_pkgs_.emplace(pkgid);
-  dep_info_.splice(dep_info_.end(), pkg_dep_info);
   installers_.emplace(pkgid, std::move(installer));
   request_pkgid_.emplace_back(pkgid);
 
@@ -202,10 +254,10 @@ bool DependencyChecker::GetDepInfoFromDB(InstallerPtr installer) {
 
 bool DependencyChecker::GetDepInfoFromXML(InstallerPtr installer) {
   std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
-  PkgQueryInterface pkg_query(pkgid, uid_, true);
+  PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
 
   bf::path xml_path =
-      bf::path(getUserManifestPath(uid_, true)) /
+      bf::path(getUserManifestPath(pkgmgr_->GetUid(), true)) /
       bf::path(pkgid + ".xml");
 
   if (!bf::exists(xml_path)) {
@@ -225,52 +277,22 @@ bool DependencyChecker::GetDepInfoFromXML(InstallerPtr installer) {
     LOG(ERROR) << "Package info manifest data has not been found.";
     return false;
   }
+  install_pkgs_[pkgid] = pkg_info->version();
+  installers_.emplace(pkgid, std::move(installer));
+  request_pkgid_.emplace_back(pkgid);
 
   std::shared_ptr<const tpk::parse::DependenciesInfo> dependencies_info =
       std::static_pointer_cast<const tpk::parse::DependenciesInfo>(
           parser.GetManifestData(tpk::application_keys::kDependenciesKey));
-  if (!dependencies_info) {
-    LOG(ERROR) << "dependencies info is null";
-    pkg_version_[pkgid] = pkg_info->version();
-    installers_.emplace(pkgid, std::move(installer));
-    request_pkgid_.emplace_back(pkgid);
+  if (!dependencies_info)
     return true;
-  }
 
-  std::list<DependencyInfo> pkg_dep_info;
   for (const auto& dependency : dependencies_info->dependencies()) {
     if (dependency.type() != kRequiredDependencyType)
       continue;
 
-    pkg_dep_info.emplace_back(pkgid, dependency.pkgid(),
-        dependency.type(), dependency.required_version());
-  }
-
-  pkg_version_[pkgid] = pkg_info->version();
-  dep_info_.splice(dep_info_.end(), pkg_dep_info);
-  installers_.emplace(pkgid, std::move(installer));
-  request_pkgid_.emplace_back(pkgid);
-
-  return true;
-}
-
-std::list<InstallerPtr> DependencyChecker::GetSortedAppInstallers() {
-  std::list<InstallerPtr> result;
-  if (!CheckMeetDependency())
-    return {};
-  if (!MakeGraph())
-    return {};
-  if (!TopologicalSort(&result))
-    return {};
-
-  return result;
-}
-
-bool DependencyChecker::MakeGraph() {
-  for (const DependencyInfo& dep_info : dep_info_) {
-    std::string from = std::get<0>(dep_info);
-    std::string to = std::get<1>(dep_info);
-    AddEdge(from, to);
+    dep_graph_[pkgid].emplace(dependency.pkgid(),
+        dependency.required_version());
   }
 
   return true;
index b268fa9c249125c77e73adf06ae80673b983d311..b8c7cd4a04bb91d67368ec9a97263462e534cb9d 100644 (file)
@@ -11,7 +11,6 @@
 #include <set>
 #include <string>
 #include <tuple>
-#include <vector>
 
 #include "common/installer/app_installer.h"
 #include "common/pkgmgr_interface.h"
@@ -22,8 +21,7 @@ typedef std::unique_ptr<AppInstaller> InstallerPtr;
 
 class DependencyChecker {
  public:
-  explicit DependencyChecker(uid_t uid, PkgMgrPtr pkgmgr)
-      : uid_(uid), pkgmgr_(pkgmgr) {}
+  explicit DependencyChecker(PkgMgrPtr pkgmgr) : pkgmgr_(pkgmgr) {}
   using DependencyInfo =
       std::tuple<std::string, std::string, std::string, std::string>;
   bool AddInstaller(InstallerPtr installer);
@@ -31,26 +29,25 @@ class DependencyChecker {
 
  private:
   bool CheckMeetDependency();
+  bool CheckRequiredBy(const std::string& pkgid,
+      const std::string& pkg_version);
+  bool CheckRequires(const std::string& pkgid);
+  bool CheckInstallPkg();
+  bool CheckUninstallPkg();
   bool DFS(const std::string& node,
            std::list<InstallerPtr>* result);
   bool GetDepInfoFromArchive(InstallerPtr installer);
   bool GetDepInfoFromDB(InstallerPtr installer);
   bool GetDepInfoFromXML(InstallerPtr installer);
-  bool MakeGraph();
   bool TopologicalSort(std::list<InstallerPtr>* result);
-  void AddEdge(const std::string& from, const std::string& to);
-  bool CheckUninstallPkgDependencyInfo();
-  bool CheckInstallPkgDependencyInfo();
 
-  std::list<DependencyInfo> dep_info_;
-  std::map<std::string, std::vector<std::string>> dep_graph_;
-  std::map<std::string, std::string> pkg_version_;
+  std::map<std::string, std::map<std::string, std::string>> dep_graph_;
+  std::map<std::string, std::string> install_pkgs_;
   std::map<std::string, InstallerPtr> installers_;
   std::list<std::string> request_pkgid_;
   std::set<std::string> uninstall_pkgs_;
   std::set<std::string> visited_;
   std::set<std::string> finished_;
-  uid_t uid_;
   PkgMgrPtr pkgmgr_;
 };
 
index 68e9747108f21e8fb1394a99d7bb77ee4f92c9d4..c714dee0d3704e0d6dff77d8f4b7d0f42397e2d1 100644 (file)
@@ -46,7 +46,7 @@ bool InstallerRunner::NeedCheckDependency() {
 }
 
 bool InstallerRunner::SortInstallers() {
-  DependencyChecker dep_checker(pkgmgr_->GetUid(), pkgmgr_);
+  DependencyChecker dep_checker(pkgmgr_);
   for (auto& installer : installers_) {
     if (!dep_checker.AddInstaller(std::move(installer))) {
       LOG(ERROR) << "Failed to add installer to dependency checker";