Remove boost dependency
[platform/core/appfw/app-installers.git] / src / common / dependency_checker.cc
1 // Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/dependency_checker.h"
6
7 #include <pkgmgr-info.h>
8
9 #include <manifest_parser/utils/logging.h>
10 #include <manifest_parser/utils/version_number.h>
11 #include <tpk_manifest_handlers/application_manifest_constants.h>
12 #include <tpk_manifest_handlers/dependencies_handler.h>
13 #include <tpk_manifest_handlers/package_handler.h>
14 #include <tpk_manifest_handlers/tpk_config_parser.h>
15
16 #include <filesystem>
17 #include <map>
18 #include <memory>
19 #include <tuple>
20 #include <utility>
21 #include <vector>
22
23 #include "common/archive_info.h"
24 #include "common/utils/pkgmgr_query.h"
25
26 namespace fs = std::filesystem;
27 using Dependency = std::tuple<std::string, std::string, std::string>;
28
29 namespace {
30
31 const char kRequiredDependencyType[] = "requires";
32
33 }  // namespace
34
35 namespace common_installer {
36
37 static std::string InvalidDependencyError(const std::string& from,
38     const std::string& to, const std::string& required_version) {
39   return "Dependency [" + from + "] -> [" + to
40       + (required_version.empty() ? "" : "(>=" + required_version + ")")
41       + "] is not met";
42 }
43
44 bool DependencyChecker::AddInstaller(InstallerPtr installer) {
45   RequestType req_type = pkgmgr_->GetRequestType(installer->GetIndex());
46   switch (req_type) {
47     case RequestType::Install:
48     case RequestType::Update:
49     case RequestType::ReadonlyUpdateInstall:
50     case RequestType::MountInstall:
51     case RequestType::MountUpdate:
52     case RequestType::Delta:
53       return GetDepInfoFromArchive(std::move(installer));
54     case RequestType::Uninstall:
55       return GetDepInfoFromDB(std::move(installer));
56     case RequestType::ReadonlyUpdateUninstall:
57       return GetDepInfoFromXML(std::move(installer));
58     default:
59       return false;
60   }
61   return true;
62 }
63
64 std::list<InstallerPtr> DependencyChecker::GetSortedAppInstallers() {
65   std::list<InstallerPtr> result;
66   if (!CheckMeetDependency())
67     return {};
68   if (!TopologicalSort(&result))
69     return {};
70
71   return result;
72 }
73
74 const std::string& DependencyChecker::GetErrorMessage() const {
75   return error_;
76 }
77
78 bool DependencyChecker::CheckMeetDependency() {
79   if (!CheckInstallPkg())
80     return false;
81   if (!CheckUninstallPkg())
82     return false;
83
84   return true;
85 }
86
87 bool DependencyChecker::CheckRequires(const std::string& pkgid) {
88   for (const auto& dep_info : dep_graph_[pkgid]) {
89     std::string require_pkgid = dep_info.first;
90     std::string require_version = dep_info.second;
91     std::string actual_pkg_version;
92     if (install_pkgs_.count(require_pkgid)) {
93       actual_pkg_version = install_pkgs_[require_pkgid];
94     } else {
95       PkgQueryInterface pkg_query(require_pkgid, pkgmgr_->GetUid());
96       if (!pkg_query.IsValid()) {
97         error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
98         return false;
99       }
100       actual_pkg_version = pkg_query.Version();
101     }
102
103     if (utils::VersionNumber(actual_pkg_version).Compare(
104         utils::VersionNumber(require_version)) < 0) {
105       error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
106       return false;
107     }
108   }
109   return true;
110 }
111
112 bool DependencyChecker::CheckRequiredBy(const std::string& pkgid,
113     const std::string& pkg_version) {
114   PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
115   if (!pkg_query.IsValid())
116     return true;
117
118   std::vector<DependencyInfo> dep_info;
119   if (!pkg_query.PackagesDependsOn(&dep_info)) {
120     error_ = "Failed to get depends on information of package";
121     return false;
122   }
123   for (const auto& info : dep_info) {
124     std::string from = std::get<0>(info);
125     std::string to = std::get<1>(info);
126     std::string type = std::get<2>(info);
127     std::string dependent_version = std::get<3>(info);
128
129     if (to != pkgid || type != kRequiredDependencyType
130         || dependent_version.empty() || install_pkgs_.count(from))
131       continue;
132
133     if (utils::VersionNumber(pkg_version).Compare(
134         utils::VersionNumber(dependent_version)) < 0) {
135       error_ = InvalidDependencyError(from, to, dependent_version);
136       return false;
137     }
138   }
139   return true;
140 }
141
142 bool DependencyChecker::CheckInstallPkg() {
143   for (const auto& install_pkg : install_pkgs_) {
144     std::string pkgid = install_pkg.first;
145     std::string pkg_version = install_pkg.second;
146     if (!CheckRequires(pkgid))
147       return false;
148     if (!CheckRequiredBy(pkgid, pkg_version))
149       return false;
150   }
151   return true;
152 }
153
154 bool DependencyChecker::CheckUninstallPkg() {
155   for (const auto& pkgid : uninstall_pkgs_) {
156     PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
157     std::vector<DependencyInfo> dep_info;
158     if (!pkg_query.PackagesDependsOn(&dep_info)) {
159       error_ = "Failed to get depends on information of package";
160       return false;
161     }
162     for (const auto& info : dep_info) {
163       std::string from = std::get<0>(info);
164       std::string to = std::get<1>(info);
165       std::string type = std::get<2>(info);
166       std::string dependent_version = std::get<3>(info);
167
168       if (to != pkgid || type != kRequiredDependencyType)
169         continue;
170       if (uninstall_pkgs_.count(from) == 0) {
171         error_ = InvalidDependencyError(from, to, dependent_version);
172         return false;
173       }
174     }
175   }
176   return true;
177 }
178
179 bool DependencyChecker::DFS(const std::string& node,
180                             std::list<InstallerPtr>* result) {
181   if (visited_.count(node)) {
182     if (finished_.count(node)) {
183       return true;
184     } else {
185       error_ = "Graph has circular dependency";
186       return false;
187     }
188   }
189   visited_.emplace(node);
190
191   for (const auto& next_node : dep_graph_[node]) {
192     std::string pkgid = next_node.first;
193     if (!DFS(pkgid, result))
194       return false;
195   }
196
197   if (installers_.count(node))
198     result->emplace_back(std::move(installers_[node]));
199
200   finished_.emplace(node);
201   return true;
202 }
203
204 bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
205   std::unique_ptr<ArchiveInfo> archive_info = installer->GetArchiveInfo();
206   if (archive_info == nullptr) {
207     error_ = "Get archive info fail";
208     return false;
209   }
210   if (!archive_info->LoadArchiveInfo()) {
211     error_ = "Load archive info fail";
212     return false;
213   }
214   std::string pkgid = archive_info->pkgid();
215   std::string version = archive_info->version();
216   std::vector<Dependency> dependencies = archive_info->dependencies();
217
218   for (const Dependency& dep : dependencies) {
219     std::string dep_pkg = std::get<0>(dep);
220     std::string type = std::get<1>(dep);
221     std::string required_version = std::get<2>(dep);
222
223     if (type != kRequiredDependencyType)
224       continue;
225
226     dep_graph_[pkgid].emplace(dep_pkg, required_version);
227   }
228
229   install_pkgs_[pkgid] = version;
230   installers_.emplace(pkgid, std::move(installer));
231   request_pkgid_.emplace_back(pkgid);
232
233   return true;
234 }
235
236 bool DependencyChecker::GetDepInfoFromDB(InstallerPtr installer) {
237   std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
238   PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
239   if (!pkg_query.IsValid()) {
240     error_ = "Package is not installed";
241     return false;
242   }
243   std::vector<DependencyInfo> dep_info;
244   if (!pkg_query.PackagesDependsOn(&dep_info)) {
245     error_ = "Failed to get depends on information of package";
246     return false;
247   }
248
249   for (const auto& info : dep_info) {
250     std::string from = std::get<0>(info);
251     std::string to = std::get<1>(info);
252     std::string type = std::get<2>(info);
253     std::string version = std::get<3>(info);
254
255     if (type != kRequiredDependencyType)
256       continue;
257
258     dep_graph_[from].emplace(to, version);
259   }
260
261   uninstall_pkgs_.emplace(pkgid);
262   installers_.emplace(pkgid, std::move(installer));
263   request_pkgid_.emplace_back(pkgid);
264
265   return true;
266 }
267
268 bool DependencyChecker::GetDepInfoFromXML(InstallerPtr installer) {
269   std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
270   PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
271
272   fs::path xml_path =
273       fs::path(getUserManifestPath(pkgmgr_->GetUid(), true)) /
274       fs::path(pkgid + ".xml");
275
276   if (!fs::exists(xml_path)) {
277     error_ = "xml path is not exist";
278     return false;
279   }
280
281   tpk::parse::TPKConfigParser parser;
282   if (!parser.ParseManifest(xml_path)) {
283     error_ = "parse fail";
284     return false;
285   }
286   std::shared_ptr<const tpk::parse::PackageInfo> pkg_info =
287       std::static_pointer_cast<const tpk::parse::PackageInfo>(
288           parser.GetManifestData(tpk::application_keys::kManifestKey));
289   if (!pkg_info) {
290     error_ = "Package info manifest data has not been found.";
291     return false;
292   }
293   install_pkgs_[pkgid] = pkg_info->version();
294   installers_.emplace(pkgid, std::move(installer));
295   request_pkgid_.emplace_back(pkgid);
296
297   std::shared_ptr<const tpk::parse::DependenciesInfo> dependencies_info =
298       std::static_pointer_cast<const tpk::parse::DependenciesInfo>(
299           parser.GetManifestData(tpk::application_keys::kDependenciesKey));
300   if (!dependencies_info)
301     return true;
302
303   for (const auto& dependency : dependencies_info->dependencies()) {
304     if (dependency.type() != kRequiredDependencyType)
305       continue;
306
307     dep_graph_[pkgid].emplace(dependency.pkgid(),
308         dependency.required_version());
309   }
310
311   return true;
312 }
313
314 bool DependencyChecker::TopologicalSort(std::list<InstallerPtr>* result) {
315   for (auto it = request_pkgid_.rbegin(); it != request_pkgid_.rend(); ++it) {
316     if (!DFS(*it, result))
317       return false;
318   }
319   result->reverse();
320   return true;
321 }
322
323 }  // namespace common_installer