Fix generating manifest when install hybrid package 28/105428/3 accepted/tizen/3.0/common/20161227.101247 accepted/tizen/3.0/ivi/20161222.024830 accepted/tizen/3.0/mobile/20161222.024711 accepted/tizen/3.0/tv/20161222.024738 accepted/tizen/3.0/wearable/20161222.024803 submit/tizen_3.0/20161221.130430
authorSangyoon Jang <s89.jang@samsung.com>
Fri, 16 Dec 2016 09:54:40 +0000 (18:54 +0900)
committerSangyoon Jang <s89.jang@samsung.com>
Mon, 19 Dec 2016 11:25:55 +0000 (03:25 -0800)
Currently, wgt-backend generate manifest file using manifest_x which is
parsed by manifest parser. This data contains only the parser knows.
However, the manifest file for native packages have many element which
are not parsed manifest parser but parsed by plugin parsers.
So the manifest generated by wgt-backend loses some elements.

This patch will make the manifest have elements as it was before.
StepGenerateXml from hybrid installer will merge original native
manifest into generated widget manifest(config.xml).

Change-Id: Iea0a68c3b695243248469f0794f62f7bec4fa757
Signed-off-by: Sangyoon Jang <s89.jang@samsung.com>
src/hybrid/CMakeLists.txt
src/hybrid/hybrid_installer.cc
src/hybrid/step/pkgmgr/step_generate_xml.cc [new file with mode: 0644]
src/hybrid/step/pkgmgr/step_generate_xml.h [new file with mode: 0644]

index e65d713..016c783 100644 (file)
@@ -1,10 +1,12 @@
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} HYBRID_SRCS)
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/step/configuration HYBRID_STEP_CONFIGURATION_SRCS)
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/step/encryption HYBRID_STEP_ENCRYPTION_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/step/pkgmgr HYBRID_STEP_PKGMGR_SRCS)
 ADD_LIBRARY(${TARGET_LIBNAME_HYBRID} STATIC
   ${HYBRID_SRCS}
   ${HYBRID_STEP_CONFIGURATION_SRCS}
-  ${HYBRID_STEP_ENCRYPTION_SRCS})
+  ${HYBRID_STEP_ENCRYPTION_SRCS}
+  ${HYBRID_STEP_PKGMGR_SRCS})
 
 TARGET_INCLUDE_DIRECTORIES(${TARGET_LIBNAME_HYBRID} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../")
 
index ed90220..5aef5e2 100644 (file)
@@ -80,6 +80,7 @@
 #include "hybrid/step/configuration/step_merge_tpk_config.h"
 #include "hybrid/step/configuration/step_stash_tpk_config.h"
 #include "hybrid/step/encryption/step_encrypt_resources.h"
+#include "hybrid/step/pkgmgr/step_generate_xml.h"
 #include "wgt/step/configuration/step_parse.h"
 #include "wgt/step/encryption/step_remove_encryption_data.h"
 #include "wgt/step/filesystem/step_copy_preview_icons.h"
@@ -112,7 +113,6 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<hybrid::configuration::StepStashTpkConfig>();
       AddStep<wgt::configuration::StepParse>(
           wgt::configuration::StepParse::ConfigLocation::RESOURCE_WGT, true);
-      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::configuration::StepParsePreload>();
       AddStep<ci::pkgmgr::StepCheckRestriction>();
       AddStep<ci::configuration::StepCheckTizenVersion>();
@@ -138,6 +138,8 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<wgt::filesystem::StepCreateSymbolicLink>();
       AddStep<tpk::filesystem::StepCreateSymbolicLink>();
       AddStep<wgt::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::security::StepRegisterSecurity>();
       AddStep<ci::pkgmgr::StepRegisterApplication>();
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
@@ -156,7 +158,6 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<hybrid::configuration::StepStashTpkConfig>();
       AddStep<wgt::configuration::StepParse>(
           wgt::configuration::StepParse::ConfigLocation::RESOURCE_WGT, true);
-      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::configuration::StepParsePreload>();
       AddStep<ci::configuration::StepCheckTizenVersion>();
       AddStep<ci::security::StepCheckSignature>();
@@ -188,6 +189,8 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<tpk::filesystem::StepCreateSymbolicLink>();
       AddStep<ci::security::StepUpdateSecurity>();
       AddStep<wgt::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::pkgmgr::StepUpdateApplication>();
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
           ci::Plugin::ActionType::Upgrade);
@@ -238,7 +241,6 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<ci::filesystem::StepDisableExternalMount>();
       AddStep<wgt::configuration::StepParse>(
           wgt::configuration::StepParse::ConfigLocation::RESOURCE_WGT, true);
-      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::configuration::StepParsePreload>();
       AddStep<ci::configuration::StepCheckTizenVersion>();
       AddStep<ci::security::StepCheckSignature>();
@@ -268,6 +270,8 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<tpk::filesystem::StepCreateSymbolicLink>();
       AddStep<ci::security::StepUpdateSecurity>();
       AddStep<wgt::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::pkgmgr::StepUpdateApplication>();
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
           ci::Plugin::ActionType::Upgrade);
@@ -309,7 +313,6 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<hybrid::configuration::StepStashTpkConfig>();
       AddStep<wgt::configuration::StepParse>(
           wgt::configuration::StepParse::ConfigLocation::RESOURCE_WGT, true);
-      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::configuration::StepParsePreload>();
       AddStep<ci::pkgmgr::StepCheckRestriction>();
       AddStep<ci::configuration::StepCheckTizenVersion>();
@@ -335,6 +338,8 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<wgt::filesystem::StepCreateSymbolicLink>();
       AddStep<tpk::filesystem::StepCreateSymbolicLink>();
       AddStep<wgt::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::security::StepRegisterSecurity>();
       AddStep<ci::pkgmgr::StepRegisterApplication>();
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
@@ -353,7 +358,6 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<hybrid::configuration::StepStashTpkConfig>();
       AddStep<wgt::configuration::StepParse>(
           wgt::configuration::StepParse::ConfigLocation::RESOURCE_WGT, true);
-      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::configuration::StepParsePreload>();
       AddStep<ci::configuration::StepCheckTizenVersion>();
       AddStep<ci::security::StepCheckSignature>();
@@ -384,6 +388,8 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<tpk::filesystem::StepCreateSymbolicLink>();
       AddStep<ci::security::StepUpdateSecurity>();
       AddStep<wgt::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::pkgmgr::StepUpdateApplication>();
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
           ci::Plugin::ActionType::Upgrade);
@@ -399,7 +405,6 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<hybrid::configuration::StepStashTpkConfig>();
       AddStep<wgt::configuration::StepParse>(
           wgt::configuration::StepParse::ConfigLocation::INSTALLED, true);
-      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::configuration::StepParsePreload>();
       AddStep<ci::configuration::StepCheckTizenVersion>();
       AddStep<ci::security::StepCheckSignature>();
@@ -410,6 +415,8 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<ci::security::StepRollbackInstallationSecurity>();
       AddStep<ci::filesystem::StepRemoveGlobalAppSymlinks>();
       AddStep<wgt::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::security::StepRegisterSecurity>();
       AddStep<ci::pkgmgr::StepRegisterApplication>();
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
@@ -427,7 +434,6 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<hybrid::configuration::StepStashTpkConfig>();
       AddStep<wgt::configuration::StepParse>(
           wgt::configuration::StepParse::ConfigLocation::INSTALLED, true);
-      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::configuration::StepParsePreload>();
       AddStep<ci::configuration::StepCheckTizenVersion>();
       AddStep<ci::security::StepCheckSignature>();
@@ -443,6 +449,8 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
       AddStep<ci::security::StepUpdateSecurity>();
       AddStep<ci::filesystem::StepRemoveGlobalAppSymlinks>();
       AddStep<wgt::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::pkgmgr::StepGenerateXml>();
+      AddStep<hybrid::configuration::StepMergeTpkConfig>();
       AddStep<ci::pkgmgr::StepUpdateApplication>();
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
           ci::Plugin::ActionType::Upgrade);
diff --git a/src/hybrid/step/pkgmgr/step_generate_xml.cc b/src/hybrid/step/pkgmgr/step_generate_xml.cc
new file mode 100644 (file)
index 0000000..7d6f42d
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "hybrid/step/pkgmgr/step_generate_xml.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <pkgmgr_parser.h>
+
+#include <common/utils/file_util.h>
+#include <common/utils/glist_range.h>
+
+#include <string>
+#include <vector>
+
+#include "hybrid/hybrid_backend_data.h"
+
+namespace ci = common_installer;
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+
+namespace {
+
+const char kXmlXPathAppExpr[] =
+    "//*[local-name()='ui-application' or local-name()='service-application' "
+    "or local-name()='widget-application' or local-name()='watch-application']";
+const std::vector<std::string> kBlackListNodes = {
+  {"author"},
+  {"description"},
+  {"profile"},
+};
+const std::vector<std::string> kNeedMergeNodes = {
+  {"manifest"},
+  {"privileges"},
+};
+const std::vector<std::pair<std::string, std::string>> kApplicationNodeNames = {
+  {"ui-application", "uiapp"},
+  {"service-application", "svcapp"},
+  {"widget-application", "widgetapp"},
+  {"watch-application", "watchapp"},
+};
+
+}  // namespace
+
+namespace hybrid {
+namespace pkgmgr {
+
+bool StepGenerateXml::LoadXmlDocument(const bf::path& wgt_xml_path,
+    const bf::path& tpk_xml_path) {
+  // trim blanks
+  xmlKeepBlanksDefault(0);
+  wgt_doc_ = xmlParseFile(wgt_xml_path.string().c_str());
+  if (!wgt_doc_) {
+    LOG(ERROR) << "Failed to parse file: " << wgt_xml_path;
+    return false;
+  }
+  tpk_doc_ = xmlParseFile(tpk_xml_path.string().c_str());
+  if (!tpk_doc_) {
+    LOG(ERROR) << "Failed to parse file: " << tpk_xml_path;
+    return false;
+  }
+  return true;
+}
+
+xmlNodePtr StepGenerateXml::GetXmlNode(const xmlDocPtr doc,
+    const std::string& name, const std::string& attr,
+    const std::string& attr_val) {
+  xmlXPathContextPtr ctxt = xmlXPathNewContext(doc);
+  if (!ctxt) {
+    LOG(ERROR) << "Failed to create XPath context";
+    return nullptr;
+  }
+
+  std::string expr = "//*[local-name()='" + name + "']";
+  if (!attr.empty() && !attr_val.empty())
+    expr.append("[@" + attr + "='" + attr_val + "']");
+
+  xmlXPathObjectPtr obj =
+      xmlXPathEvalExpression((const xmlChar*)expr.c_str(), ctxt);
+  if (!obj || !obj->nodesetval || !obj->nodesetval->nodeNr) {
+    xmlXPathFreeContext(ctxt);
+    return nullptr;
+  }
+
+  xmlNodePtr node = obj->nodesetval->nodeTab[0];
+  xmlXPathFreeObject(obj);
+  xmlXPathFreeContext(ctxt);
+
+  return node;
+}
+
+void StepGenerateXml::MergeXmlNode(xmlNodePtr node1, xmlNodePtr node2) {
+  xmlNodePtr last = xmlGetLastChild(node1);
+  xmlNodePtr next;
+  // merge node2's child into node1
+  for (xmlNodePtr cur = node2->children; cur; cur = next) {
+    next = cur->next;
+    if (std::find(kBlackListNodes.begin(), kBlackListNodes.end(),
+        reinterpret_cast<const char*>(cur->name)) != kBlackListNodes.end())
+      continue;
+    // to avoid duplicate
+    if (std::find(kNeedMergeNodes.begin(), kNeedMergeNodes.end(),
+        reinterpret_cast<const char*>(cur->name)) != kNeedMergeNodes.end())
+      continue;
+    xmlAddNextSibling(last, cur);
+    last = last->next;
+  }
+}
+
+void StepGenerateXml::SetXmlNodeAttribute(xmlNodePtr node,
+    const std::string& attr, const std::string& attr_val) {
+  xmlSetProp(node, reinterpret_cast<const xmlChar*>(attr.c_str()),
+      reinterpret_cast<const xmlChar*>(attr_val.c_str()));
+}
+
+ci::Step::Status StepGenerateXml::process() {
+  bf::path wgt_xml_path = context_->xml_path.get();
+  bf::path tpk_xml_path = context_->pkg_path.get() / "tizen-manifest.xml";
+
+  if (!LoadXmlDocument(wgt_xml_path, tpk_xml_path))
+    return Step::Status::MANIFEST_ERROR;
+
+  for (auto& entry : kNeedMergeNodes) {
+    xmlNodePtr tpk_node = GetXmlNode(tpk_doc_, entry);
+    if (tpk_node == nullptr)
+      continue;
+    // TODO(s89.jang): If cannot find node from wgt doc, merge tpk node itself
+    // instead of merging its child nodes.
+    xmlNodePtr wgt_node = GetXmlNode(wgt_doc_, entry);
+    MergeXmlNode(wgt_node, tpk_node);
+  }
+
+  // set app's executable path
+  HybridBackendData* data =
+      static_cast<HybridBackendData*>(context_->backend_data.get());
+  manifest_x* tpk_data = data->tpk_manifest_data.get();
+  for (application_x* app :
+      GListRange<application_x*>(tpk_data->application)) {
+    auto r = std::find_if(kApplicationNodeNames.begin(),
+        kApplicationNodeNames.end(),
+        [app](const std::pair<std::string, std::string>& e) {
+          return strcmp(e.second.c_str(), app->component_type) == 0;
+        });
+    if (r == kApplicationNodeNames.end()) {
+      LOG(WARNING) << "Cannot find component type!";
+      continue;
+    }
+    xmlNodePtr node = GetXmlNode(wgt_doc_, (*r).first, "appid", app->appid);
+    SetXmlNodeAttribute(node, "exec", app->exec);
+  }
+
+  if (xmlSaveFormatFile(wgt_xml_path.string().c_str(), wgt_doc_, 1) == -1) {
+    LOG(ERROR) << "Cannot write xml file";
+    return Step::Status::MANIFEST_ERROR;
+  }
+
+  if (pkgmgr_parser_check_manifest_validation(
+      wgt_xml_path.string().c_str()) != 0) {
+    LOG(ERROR) << "Merged manifest is not valid";
+    return Step::Status::MANIFEST_ERROR;
+  }
+
+  return Status::OK;
+}
+
+ci::Step::Status StepGenerateXml::precheck() {
+  bf::path wgt_xml_path = context_->xml_path.get();
+  if (!bf::exists(wgt_xml_path)) {
+    LOG(ERROR) << "Converted config file not found: " << wgt_xml_path;
+    return Step::Status::MANIFEST_ERROR;
+  }
+
+  bf::path tpk_xml_path = context_->pkg_path.get() / "tizen-manifest.xml";
+  if (!bf::exists(tpk_xml_path)) {
+    LOG(ERROR) << "Native manifest file not found: " << tpk_xml_path;
+    return Step::Status::MANIFEST_ERROR;
+  }
+
+  return Status::OK;
+}
+
+}  // namespace pkgmgr
+}  // namespace hybrid
diff --git a/src/hybrid/step/pkgmgr/step_generate_xml.h b/src/hybrid/step/pkgmgr/step_generate_xml.h
new file mode 100644 (file)
index 0000000..b2a0f6e
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef HYBRID_STEP_PKGMGR_STEP_GENERATE_XML_H_
+#define HYBRID_STEP_PKGMGR_STEP_GENERATE_XML_H_
+
+#include <boost/filesystem.hpp>
+
+#include <common/step/step.h>
+#include <manifest_parser/utils/logging.h>
+#include <libxml/tree.h>
+
+#include <string>
+
+namespace hybrid {
+namespace pkgmgr {
+
+class StepGenerateXml : public common_installer::Step {
+ public:
+  using Step::Step;
+  Status process() override;
+  Status clean() override { return Status::OK; }
+  Status undo() override { return Status::OK; }
+  Status precheck() override;
+
+ private:
+  bool LoadXmlDocument(const boost::filesystem::path& wgt_xml_path,
+      const boost::filesystem::path& tpk_xml_path);
+  xmlNodePtr GetXmlNode(const xmlDocPtr doc, const std::string& name,
+      const std::string& attr = {}, const std::string& attr_val = {});
+  void MergeXmlNode(xmlNodePtr node1, xmlNodePtr node2);
+  void SetXmlNodeAttribute(xmlNodePtr node, const std::string& attr,
+      const std::string& attr_val);
+
+  xmlDocPtr wgt_doc_;
+  xmlDocPtr tpk_doc_;
+
+  STEP_NAME(GenerateXml2);
+};
+
+}  // namespace pkgmgr
+}  // namespace hybrid
+
+#endif  // HYBRID_STEP_PKGMGR_STEP_GENERATE_XML_H_