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.
5 #include "common/dependency_checker.h"
7 #include <boost/filesystem/path.hpp>
9 #include <pkgmgr-info.h>
11 #include <manifest_parser/utils/logging.h>
12 #include <manifest_parser/utils/version_number.h>
13 #include <tpk_manifest_handlers/application_manifest_constants.h>
14 #include <tpk_manifest_handlers/dependencies_handler.h>
15 #include <tpk_manifest_handlers/package_handler.h>
16 #include <tpk_manifest_handlers/tpk_config_parser.h>
24 #include "common/archive_info.h"
25 #include "common/utils/pkgmgr_query.h"
27 namespace bf = boost::filesystem;
29 using Dependency = std::tuple<std::string, std::string, std::string>;
33 const char kRequiredDependencyType[] = "requires";
37 namespace common_installer {
39 static std::string InvalidDependencyError(const std::string& from,
40 const std::string& to, const std::string& required_version) {
41 return "Dependency [" + from + "] -> [" + to
42 + (required_version.empty() ? "" : "(>=" + required_version + ")")
46 bool DependencyChecker::AddInstaller(InstallerPtr installer) {
47 RequestType req_type = pkgmgr_->GetRequestType(installer->GetIndex());
49 case RequestType::Install:
50 case RequestType::Update:
51 case RequestType::ReadonlyUpdateInstall:
52 case RequestType::MountInstall:
53 case RequestType::MountUpdate:
54 case RequestType::Delta:
55 return GetDepInfoFromArchive(std::move(installer));
56 case RequestType::Uninstall:
57 return GetDepInfoFromDB(std::move(installer));
58 case RequestType::ReadonlyUpdateUninstall:
59 return GetDepInfoFromXML(std::move(installer));
66 std::list<InstallerPtr> DependencyChecker::GetSortedAppInstallers() {
67 std::list<InstallerPtr> result;
68 if (!CheckMeetDependency())
70 if (!TopologicalSort(&result))
76 const std::string& DependencyChecker::GetErrorMessage() const {
80 bool DependencyChecker::CheckMeetDependency() {
81 if (!CheckInstallPkg())
83 if (!CheckUninstallPkg())
89 bool DependencyChecker::CheckRequires(const std::string& pkgid) {
90 for (const auto& dep_info : dep_graph_[pkgid]) {
91 std::string require_pkgid = dep_info.first;
92 std::string require_version = dep_info.second;
93 std::string actual_pkg_version;
94 if (install_pkgs_.count(require_pkgid)) {
95 actual_pkg_version = install_pkgs_[require_pkgid];
97 PkgQueryInterface pkg_query(require_pkgid, pkgmgr_->GetUid());
98 if (!pkg_query.IsValid()) {
99 error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
102 actual_pkg_version = pkg_query.Version();
105 if (utils::VersionNumber(actual_pkg_version).Compare(
106 utils::VersionNumber(require_version)) < 0) {
107 error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
114 bool DependencyChecker::CheckRequiredBy(const std::string& pkgid,
115 const std::string& pkg_version) {
116 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
117 if (!pkg_query.IsValid())
120 std::vector<DependencyInfo> dep_info;
121 if (!pkg_query.PackagesDependsOn(&dep_info)) {
122 error_ = "Failed to get depends on information of package";
125 for (const auto& info : dep_info) {
126 std::string from = std::get<0>(info);
127 std::string to = std::get<1>(info);
128 std::string type = std::get<2>(info);
129 std::string dependent_version = std::get<3>(info);
131 if (to != pkgid || type != kRequiredDependencyType
132 || dependent_version.empty() || install_pkgs_.count(from))
135 if (utils::VersionNumber(pkg_version).Compare(
136 utils::VersionNumber(dependent_version)) < 0) {
137 error_ = InvalidDependencyError(from, to, dependent_version);
144 bool DependencyChecker::CheckInstallPkg() {
145 for (const auto& install_pkg : install_pkgs_) {
146 std::string pkgid = install_pkg.first;
147 std::string pkg_version = install_pkg.second;
148 if (!CheckRequires(pkgid))
150 if (!CheckRequiredBy(pkgid, pkg_version))
156 bool DependencyChecker::CheckUninstallPkg() {
157 for (const auto& pkgid : uninstall_pkgs_) {
158 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
159 std::vector<DependencyInfo> dep_info;
160 if (!pkg_query.PackagesDependsOn(&dep_info)) {
161 error_ = "Failed to get depends on information of package";
164 for (const auto& info : dep_info) {
165 std::string from = std::get<0>(info);
166 std::string to = std::get<1>(info);
167 std::string type = std::get<2>(info);
168 std::string dependent_version = std::get<3>(info);
170 if (to != pkgid || type != kRequiredDependencyType)
172 if (uninstall_pkgs_.count(from) == 0) {
173 error_ = InvalidDependencyError(from, to, dependent_version);
181 bool DependencyChecker::DFS(const std::string& node,
182 std::list<InstallerPtr>* result) {
183 if (visited_.count(node)) {
184 if (finished_.count(node)) {
187 error_ = "Graph has circular dependency";
191 visited_.emplace(node);
193 for (const auto& next_node : dep_graph_[node]) {
194 std::string pkgid = next_node.first;
195 if (!DFS(pkgid, result))
199 if (installers_.count(node))
200 result->emplace_back(std::move(installers_[node]));
202 finished_.emplace(node);
206 bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
207 std::unique_ptr<ArchiveInfo> archive_info = installer->GetArchiveInfo();
208 if (archive_info == nullptr) {
209 error_ = "Get archive info fail";
212 if (!archive_info->LoadArchiveInfo()) {
213 error_ = "Load archive info fail";
216 std::string pkgid = archive_info->pkgid();
217 std::string version = archive_info->version();
218 std::vector<Dependency> dependencies = archive_info->dependencies();
220 for (const Dependency& dep : dependencies) {
221 std::string dep_pkg = std::get<0>(dep);
222 std::string type = std::get<1>(dep);
223 std::string required_version = std::get<2>(dep);
225 if (type != kRequiredDependencyType)
228 dep_graph_[pkgid].emplace(dep_pkg, required_version);
231 install_pkgs_[pkgid] = version;
232 installers_.emplace(pkgid, std::move(installer));
233 request_pkgid_.emplace_back(pkgid);
238 bool DependencyChecker::GetDepInfoFromDB(InstallerPtr installer) {
239 std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
240 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
241 if (!pkg_query.IsValid()) {
242 error_ = "Package is not installed";
245 std::vector<DependencyInfo> dep_info;
246 if (!pkg_query.PackagesDependsOn(&dep_info)) {
247 error_ = "Failed to get depends on information of package";
251 for (const auto& info : dep_info) {
252 std::string from = std::get<0>(info);
253 std::string to = std::get<1>(info);
254 std::string type = std::get<2>(info);
255 std::string version = std::get<3>(info);
257 if (type != kRequiredDependencyType)
260 dep_graph_[from].emplace(to, version);
263 uninstall_pkgs_.emplace(pkgid);
264 installers_.emplace(pkgid, std::move(installer));
265 request_pkgid_.emplace_back(pkgid);
270 bool DependencyChecker::GetDepInfoFromXML(InstallerPtr installer) {
271 std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
272 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
275 bf::path(getUserManifestPath(pkgmgr_->GetUid(), true)) /
276 bf::path(pkgid + ".xml");
278 if (!bf::exists(xml_path)) {
279 error_ = "xml path is not exist";
283 tpk::parse::TPKConfigParser parser;
284 if (!parser.ParseManifest(xml_path)) {
285 error_ = "parse fail";
288 std::shared_ptr<const tpk::parse::PackageInfo> pkg_info =
289 std::static_pointer_cast<const tpk::parse::PackageInfo>(
290 parser.GetManifestData(tpk::application_keys::kManifestKey));
292 error_ = "Package info manifest data has not been found.";
295 install_pkgs_[pkgid] = pkg_info->version();
296 installers_.emplace(pkgid, std::move(installer));
297 request_pkgid_.emplace_back(pkgid);
299 std::shared_ptr<const tpk::parse::DependenciesInfo> dependencies_info =
300 std::static_pointer_cast<const tpk::parse::DependenciesInfo>(
301 parser.GetManifestData(tpk::application_keys::kDependenciesKey));
302 if (!dependencies_info)
305 for (const auto& dependency : dependencies_info->dependencies()) {
306 if (dependency.type() != kRequiredDependencyType)
309 dep_graph_[pkgid].emplace(dependency.pkgid(),
310 dependency.required_version());
316 bool DependencyChecker::TopologicalSort(std::list<InstallerPtr>* result) {
317 for (auto it = request_pkgid_.rbegin(); it != request_pkgid_.rend(); ++it) {
318 if (!DFS(*it, result))
325 } // namespace common_installer