Add TPK backend 86/35086/11
authorYoumin Ha <youmin.ha@samsung.com>
Fri, 30 Jan 2015 04:38:00 +0000 (13:38 +0900)
committerPawel Sikorski <p.sikorski@samsung.com>
Wed, 25 Feb 2015 14:43:46 +0000 (06:43 -0800)
Native tpk backend implementation: First version.
Only simple tizen-manifest.xml format can be parsed for now.

Signed-Off-By: Youmin Ha <youmin.ha@samsung.com>
Change-Id: I95037fa6b08639c6dd008d0ffb796cfd375c8060

15 files changed:
CMakeLists.txt
packaging/app-installers.spec
src/CMakeLists.txt
src/tpk/CMakeLists.txt [new file with mode: 0644]
src/tpk/exception.h [new file with mode: 0644]
src/tpk/main.cc [new file with mode: 0644]
src/tpk/manifest_parser.cc [new file with mode: 0644]
src/tpk/manifest_parser.h [new file with mode: 0644]
src/tpk/step/step_parse.cc [new file with mode: 0644]
src/tpk/step/step_parse.h [new file with mode: 0644]
src/tpk/step/step_symbolic_link.cc [new file with mode: 0644]
src/tpk/step/step_symbolic_link.h [new file with mode: 0644]
src/tpk/task.cc [new file with mode: 0644]
src/tpk/task.h [new file with mode: 0644]
src/tpk/xml_nodes.h [new file with mode: 0644]

index 7d037f4..c2050a2 100644 (file)
@@ -28,6 +28,7 @@ SET(TARGET_LIBNAME_WIDGET_MANIFEST_PARSER "common-installer-widget-manifest-pars
 SET(TARGET_WGT_BACKEND "wgt-backend")
 SET(TARGET_XPK_BACKEND "xpk-backend")
 SET(TARGET_NATIVE_BACKEND "native-backend")
+SET(TARGET_TPK_BACKEND "tpk-backend")
 
 ADD_DEFINITIONS("-Wall")
 ADD_DEFINITIONS("-Wextra")
index 25f1741..53fc9d1 100644 (file)
@@ -43,6 +43,12 @@ Summary: Backend of XPK files
 %description -n xpk-backend
 Backend for standard widget files XPK
 
+%package -n tpk-backend
+Summary: Backend of TPK files
+
+%description -n tpk-backend
+Backend for tizen package files
+
 %prep
 %setup -q
 
@@ -58,6 +64,7 @@ make %{?_smp_mflags}
 mkdir -p %{buildroot}/etc/package-manager/backend
 ln -s %{_bindir}/wgt-backend %{buildroot}%{_sysconfdir}/package-manager/backend/wgt
 ln -s %{_bindir}/xpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/xpk
+ln -s %{_bindir}/tpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/tpk
 
 %post -p /sbin/ldconfig
 
@@ -79,3 +86,8 @@ ln -s %{_bindir}/xpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/
 
 %files -n xpk-backend
 %{_sysconfdir}/package-manager/backend/xpk
+
+%files -n tpk-backend
+%{_sysconfdir}/package-manager/backend/tpk
+%{_bindir}/tpk-backend
+
index 2ae5de0..e35d46a 100644 (file)
@@ -3,5 +3,6 @@ ADD_SUBDIRECTORY(signature)
 ADD_SUBDIRECTORY(utils)
 ADD_SUBDIRECTORY(wgt)
 ADD_SUBDIRECTORY(widget-manifest-parser)
+ADD_SUBDIRECTORY(tpk)
 #ADD_SUBDIRECTORY(xpk)
 #ADD_SUBDIRECTORY(native)
diff --git a/src/tpk/CMakeLists.txt b/src/tpk/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c2c4689
--- /dev/null
@@ -0,0 +1,31 @@
+IF(NOT DEFINED TARGET_TPK_BACKEND)
+  SET(TARGET_TPK_BACKEND "tpk-backend")
+ENDIF(NOT DEFINED TARGET_TPK_BACKEND)
+
+SET(TARGET_TPK ${TARGET_TPK_BACKEND})
+OPTION(HOSTTEST "Option for the test on the host PC" OFF)
+SET(SRCS
+    main.cc
+    task.cc
+    step/step_parse.cc
+    step/step_symbolic_link.cc
+    manifest_parser.cc
+)
+ADD_EXECUTABLE(${TARGET_TPK} ${SRCS})
+
+SET(TPK_LDFLAGS -rdynamic)
+IF(${HOSTTEST})
+  MESSAGE("Host Test mode.")
+SET(TPK_CFLAGS ${TPK_CFLAGS} -DHOSTTEST)
+  SET(MOCK_MODULES test/mock_pkgmgr_installer.c)
+SET(SRCS ${SRCS} ${MOCK_MODULES})
+
+ELSE(${HOSTTEST})
+  SET(TPK_CFLAGS ${TPK_CFLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/../)
+  ADD_DEFINITIONS(${TPK_CFLAGS})
+ENDIF(${HOSTTEST})
+
+APPLY_PKG_CONFIG(${TARGET_TPK} PUBLIC PKGMGR_DEPS)
+TARGET_LINK_LIBRARIES(${TARGET_TPK} PUBLIC ${TARGET_LIBNAME_COMMON})
+
+INSTALL(TARGETS ${TARGET_TPK} DESTINATION ${BINDIR})
diff --git a/src/tpk/exception.h b/src/tpk/exception.h
new file mode 100644 (file)
index 0000000..34c1d80
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_EXCEPTION_H_
+#define TPK_EXCEPTION_H_
+
+#include <execinfo.h>
+#include <string.h>
+#include <unistd.h>
+#include <exception>
+#include <iostream>
+#include "utils/logging.h"
+
+namespace tpk {
+
+class Exception: public std::exception {
+SCOPE_LOG_TAG(UncaughtException)
+
+ public:
+  Exception() {
+    this->message_ = nullptr;
+    StoreStackTrace();
+  }
+  explicit Exception(const char *message) {
+    this->message_ = strdup(message);
+    StoreStackTrace();
+  }
+  ~Exception() {
+    if (message_) free(message_);
+  }
+  virtual void StoreStackTrace() {
+    stack_size_ = backtrace(stack_, kMaxStackSize);
+  }
+  virtual void PrintStackTrace() {
+    if (message_) {
+      LOG(ERROR) << message_;
+    }
+    // Exclude top 1 stack entry (storeStackTrace)
+    backtrace_symbols_fd(stack_+1, stack_size_-1, STDERR_FILENO);
+  }
+
+
+ protected:
+  char* message_;
+
+
+ private:
+  static const size_t kMaxStackSize = 100;
+  size_t stack_size_;
+  void *stack_[kMaxStackSize];
+};
+
+}  // namespace tpk
+#endif  // TPK_EXCEPTION_H_
diff --git a/src/tpk/main.cc b/src/tpk/main.cc
new file mode 100644 (file)
index 0000000..30e935f
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include <iostream>
+#include <cerrno>
+#include "tpk/task.h"
+#include "tpk/exception.h"
+
+
+int main(const int argc, char* argv[]) {
+  try {
+    // Create a task to do
+    tpk::Task t(argc, argv);
+
+    // Do the task
+    t.Run();
+  } catch(tpk::Exception &e) {
+    e.PrintStackTrace();
+    return -1;
+  }
+  return 0;
+}
diff --git a/src/tpk/manifest_parser.cc b/src/tpk/manifest_parser.cc
new file mode 100644 (file)
index 0000000..74d8ae3
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+
+#include "tpk/manifest_parser.h"
+#include <libxml/xmlreader.h>
+#include <iostream>
+#include <vector>
+#include "tpk/xml_nodes.h"
+
+namespace tpk {
+
+
+template <typename T>
+void ManifestParser::CheckAndSetNode(xmlTextReaderPtr reader,
+    const char* name,
+    const T& xmlNode) {
+  T& node = const_cast<T&>(xmlNode);
+  if (xmlStrEqual(reinterpret_cast<const xmlChar*>(name),
+                      xmlTextReaderConstName(reader)) &&
+          xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
+    node.Init(reader);
+  }
+}
+
+
+template <typename T>
+void ManifestParser::CheckAndAppendNode(xmlTextReaderPtr reader,
+    const char* name,
+    const std::vector<T*> &v) {
+  if (xmlStrEqual(reinterpret_cast<const xmlChar*>(name),
+                      xmlTextReaderConstName(reader)) &&
+          xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
+    T *p = new T();
+    p->Init(reader);
+    std::vector<T*>& _v = const_cast<std::vector<T*>&>(v);
+    _v.push_back(p);
+  }
+}
+
+
+void ManifestParser::ProcessNode(xmlTextReaderPtr reader) {
+  // For each node, find required node names and get data
+  CheckAndSetNode(reader, "manifest", manifest);
+  CheckAndSetNode(reader, "ui-application", manifest.ui_application);
+  CheckAndSetNode(reader, "icon", manifest.ui_application.icon);
+  CheckAndSetNode(reader, "label", manifest.ui_application.label);
+  CheckAndSetNode(reader, "privileges", manifest.privileges);
+  CheckAndAppendNode(reader, "privilege", manifest.privileges.v_privilege);
+}
+
+
+void ManifestParser::StreamFile(const char* filePath) {
+  xmlTextReaderPtr reader;
+  int ret;
+
+  // TODO(youmin.ha@samsung.com): add DTD validation
+  reader = xmlReaderForFile(filePath, NULL, 0);
+  if (reader == nullptr) {
+    throw FileOpenFailureException();
+  } else {
+    ret = xmlTextReaderRead(reader);
+    while (ret == 1) {
+      ProcessNode(reader);
+      ret = xmlTextReaderRead(reader);
+    }
+    xmlFreeTextReader(reader);
+    if (ret != 0) {
+      throw ParseFailureException();
+    }
+  }
+}
+
+
+/* constructor
+ */
+ManifestParser::ManifestParser(const char* filePath) {
+  LIBXML_TEST_VERSION
+
+  StreamFile(filePath);
+
+  xmlCleanupParser();
+  xmlMemoryDump();
+}
+
+
+/* destructor
+ */
+ManifestParser::~ManifestParser() {
+}
+
+
+}  // namespace tpk
diff --git a/src/tpk/manifest_parser.h b/src/tpk/manifest_parser.h
new file mode 100644 (file)
index 0000000..c982340
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_MANIFEST_PARSER_H_
+#define TPK_MANIFEST_PARSER_H_
+
+#include <boost/filesystem.hpp>
+#include <vector>
+#include "tpk/xml_nodes.h"
+#include "tpk/exception.h"
+
+
+namespace tpk {
+
+/* Internal exceptions */
+class FileOpenFailureException : public Exception {};
+class ParseFailureException : public Exception {};
+
+
+class ManifestParser {
+ public:
+  explicit ManifestParser(const char *manifestFilePath);
+  ~ManifestParser();
+  XmlNodeManifest manifest;
+
+
+ private:
+  template <typename T> void CheckAndSetNode(
+      xmlTextReaderPtr reader, const char* name, const T &xmlNode);
+  template <typename T> void CheckAndAppendNode(
+      xmlTextReaderPtr reader, const char* name, const std::vector<T*> &v);
+  void ProcessNode(xmlTextReaderPtr reader);
+  void StreamFile(const char* filePath);
+};
+
+}  // namespace tpk
+#endif  // TPK_MANIFEST_PARSER_H_
diff --git a/src/tpk/step/step_parse.cc b/src/tpk/step/step_parse.cc
new file mode 100644 (file)
index 0000000..b47cef1
--- /dev/null
@@ -0,0 +1,151 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/step/step_parse.h"
+#include <boost/filesystem.hpp>
+#include <string>
+#include <vector>
+#include "common/context_installer.h"
+#include "common/step/step.h"
+#include "tpk/manifest_parser.h"
+#include "tpk/xml_nodes.h"
+#include "utils/logging.h"
+
+using std::vector;
+
+namespace tpk {
+namespace step {
+
+namespace {
+  const char kManifestFileName[] = "tizen-manifest.xml";
+}  // namespace
+
+SCOPE_LOG_TAG(StepParse)
+
+/* short namespace/class name */
+typedef common_installer::Step::Status Status;
+using boost::filesystem::path;
+
+
+/* Internal exceptions */
+class FileNotFoundException : public std::exception {};
+
+
+/* process()
+ * Parse tizen-manifest.xml and get the data from it
+ * Store the data into the context_
+ */
+Status StepParse::process() {
+  try {
+    boost::filesystem::path mPath  = GetManifestFilePath(
+        context_->unpacked_dir_path());
+    ManifestParser m(mPath.c_str());
+    SetContextByManifestParser(m);
+  } catch (FileNotFoundException &e) {
+    return Status::ERROR;
+  } catch (FileOpenFailureException &e) {
+    return Status::ERROR;
+  }
+  return Status::OK;
+}
+
+
+/* in parse() : Get manifest file path from the package unzipped directory
+ */
+boost::filesystem::path StepParse::GetManifestFilePath(
+    const boost::filesystem::path& dir) {
+  path mPath(dir);
+  mPath /= kManifestFileName;
+
+  LOG(INFO) << "manifest file path: " << mPath;
+  if (!boost::filesystem::exists(mPath)) {
+    LOG(ERROR) << kManifestFileName << " not found from the package";
+    throw FileNotFoundException();
+  }
+  return mPath;  // object copy
+}
+
+
+/* Read manifest xml, and set up context_ object
+ */
+void StepParse::SetContextByManifestParser(const ManifestParser &m) {
+  const XmlNodeManifest& manifest = m.manifest;
+  LOG(DEBUG) << "Parse manifest xml values:";
+  LOG(DEBUG) << "xmlns(" << manifest.xmlns << ") api_version(" <<
+      manifest.api_version << ") package(" << manifest.package <<
+      ") version(" << manifest.version << ")";
+
+  // set context_
+  context_->config_data()->set_application_name(
+      std::string(reinterpret_cast<char*>(manifest.ui_application.label.data)));
+  context_->config_data()->set_required_version(
+      std::string(reinterpret_cast<char*>(manifest.api_version)));
+
+  context_->set_pkgid(std::string(reinterpret_cast<char*>(manifest.package)));
+
+  // set context_->manifest_data()
+  SetPkgInfoManifest(context_->manifest_data(), manifest);
+}
+
+void StepParse::SetPkgInfoManifest(manifest_x* m,
+    const XmlNodeManifest &manifest) {
+  // Common values
+  m->label =  static_cast<label_x*>
+    (calloc(1, sizeof(label_x)));
+  m->description =  static_cast<description_x*>
+    (calloc(1, sizeof(description_x)));
+  m->privileges =  static_cast<privileges_x*>
+    (calloc(1, sizeof(privileges_x)));
+  m->privileges->next = nullptr;
+  m->privileges->privilege = nullptr;
+
+  // Basic values
+  m->package = strdup(reinterpret_cast<char*>(manifest.package));
+  m->type = strdup("tpk");
+  m->version = strdup(reinterpret_cast<char*>(manifest.version));
+  m->label->name = strdup(
+      reinterpret_cast<char*>(manifest.ui_application.label.name));
+  // TODO(youmin.ha@samsung.com): get name from XML if exists
+  m->description->name = nullptr;
+  m->mainapp_id = strdup(
+      reinterpret_cast<char*>(manifest.ui_application.appid));
+
+  // Privileges
+  vector<XmlNodePrivilege *> vp =
+      const_cast<XmlNodeManifest &>(manifest).privileges.getPrivilegeVector();
+  vector<XmlNodePrivilege *>::iterator it;
+  for (it = vp.begin(); it != vp.end(); it++) {
+    privilege_x *p =
+        static_cast<privilege_x *>(calloc(1, sizeof(privilege_x)));
+    // privilege data text
+    p->text = strdup(reinterpret_cast<char*>((*it)->data));
+    LISTADD(m->privileges->privilege, p);
+    LOG(INFO) << "add privilege: " << p->text;
+  }
+
+  // Other app data (null initialization)
+  m->serviceapplication = nullptr;  // ignore service application
+  m->uiapplication = static_cast<uiapplication_x*>
+    (calloc (1, sizeof(uiapplication_x)));
+  m->uiapplication->icon = static_cast<icon_x*>
+    (calloc(1, sizeof(icon_x)));
+  m->uiapplication->label = static_cast<label_x*>
+    (calloc(1, sizeof(label_x)));
+  m->description = static_cast<description_x*>
+    (calloc(1, sizeof(description_x)));
+  m->uiapplication->appcontrol = nullptr;
+
+  m->uiapplication->appid = strdup(
+      reinterpret_cast<char*>(manifest.ui_application.appid));
+  m->uiapplication->exec = strdup(
+      reinterpret_cast<char*>(manifest.ui_application.exec));
+  m->uiapplication->type = strdup(
+      reinterpret_cast<char*>(manifest.ui_application.type));
+
+  m->uiapplication->label->name = strdup(
+      reinterpret_cast<char*>(manifest.ui_application.label.data));
+  m->uiapplication->icon->name = strdup(
+      reinterpret_cast<char*>(manifest.ui_application.icon.data));
+  m->uiapplication->next = nullptr;
+}
+
+}  // namespace step
+}  // namespace tpk
diff --git a/src/tpk/step/step_parse.h b/src/tpk/step/step_parse.h
new file mode 100644 (file)
index 0000000..0bb9d56
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_STEP_STEP_PARSE_H_
+#define TPK_STEP_STEP_PARSE_H_
+
+#include <boost/filesystem.hpp>
+#include "common/step/step.h"
+#include "tpk/manifest_parser.h"
+
+namespace tpk {
+namespace step {
+
+class StepParse : public common_installer::Step {
+ public:
+  using Step::Step;
+
+  Status process()  override;
+  Status clean()    override { return Status::OK; };
+  Status undo()     override { return Status::OK; };
+
+
+ private:
+  boost::filesystem::path
+    GetManifestFilePath(const boost::filesystem::path& dir);
+  void SetContextByManifestParser(const ManifestParser &m);
+  void SetPkgInfoManifest(manifest_x* m, const XmlNodeManifest &manifest);
+};
+
+}  // namespace step
+}  // namespace tpk
+
+#endif  // TPK_STEP_STEP_PARSE_H_
diff --git a/src/tpk/step/step_symbolic_link.cc b/src/tpk/step/step_symbolic_link.cc
new file mode 100644 (file)
index 0000000..8e10f01
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/step/step_symbolic_link.h"
+#include <boost/filesystem.hpp>
+#include <iostream>
+#include "common/step/step.h"
+#include "common/app_installer.h"
+#include "common/context_installer.h"
+#include "common/utils.h"
+#include "utils/logging.h"
+
+
+namespace tpk {
+namespace step {
+
+namespace fs = boost::filesystem;
+using common_installer::ContextInstaller;
+typedef common_installer::Step::Status Status;
+
+SCOPE_LOG_TAG(SymbolicLink)
+
+namespace {
+
+template <typename T>
+bool CreateSymLink(T *app, ContextInstaller* context) {
+  boost::system::error_code error;
+
+  for (; app != nullptr; app=app->next) {
+    fs::path bindir = fs::path(context->pkg_path()) / fs::path(app->appid) /
+        fs::path("bin");
+    LOG(INFO) << "Creating dir: " << bindir;
+    if (!utils::CreateDir(bindir)) {
+      LOG(ERROR) << "Directory creation failure";
+      return false;
+    }
+
+    // Make a symlink with the name of appid, pointing exec file
+    fs::path symlink_path = bindir / fs::path(app->appid);
+    LOG(INFO) << "Creating symlink pointing " << symlink_path  << " to " <<
+        app->exec;
+    fs::create_symlink(fs::path(app->exec), symlink_path, error);
+    if (error) {
+      LOG(ERROR) << "Symlink creation failure";
+      return false;
+    }
+
+    // Give a execution permission to the original executable
+    fs::path exec_path = bindir / fs::path(app->exec);
+    LOG(INFO) << "Giving exec permission to " << exec_path;
+    fs::permissions(exec_path, fs::owner_all |
+        fs::group_read | fs::group_exe |
+        fs::others_read | fs::others_exe, error);
+    if (error) {
+      LOG(ERROR) << "Permission change failure";
+      return false;
+    }
+  }
+  return true;
+}
+
+
+template <typename T>
+bool RemoveSymLink(T *app, ContextInstaller* context) {
+  /* NOTE: Unlike WRT app, tpk apps have bin/ directory by default.
+   * So we don't remove the bin/ directory itself.
+   */
+  for (; app != nullptr; app=app->next) {
+    fs::path exec_path = fs::path(context->pkg_path()) /
+        fs::path(app->appid) / fs::path("bin");
+    fs::remove_all(exec_path / fs::path(app->appid));
+  }
+  return true;
+}
+
+}  // namespace
+
+
+
+Status StepSymbolicLink::process() {
+  // Get manifest_x
+  manifest_x *m = context_->manifest_data();
+  if (!m) {
+    LOG(ERROR) << "manifest_x is null";
+    return Status::ERROR;
+  }
+
+  // get ui-app and service-app
+  uiapplication_x *uiapp = m->uiapplication;
+  serviceapplication_x *svcapp = m->serviceapplication;
+  if (!(uiapp || svcapp)) {
+    LOG(ERROR) << "Neither ui-application nor service-application exists";
+    return Status::ERROR;
+  }
+  if (!CreateSymLink(uiapp, context_)) return Status::ERROR;
+  if (!CreateSymLink(svcapp, context_)) return Status::ERROR;
+
+  return Status::OK;
+}
+
+
+Status StepSymbolicLink::clean() {
+  return Status::OK;
+}
+
+
+Status StepSymbolicLink::undo() {
+  manifest_x* m = context_->manifest_data();
+  uiapplication_x *uiapp = m->uiapplication;
+  serviceapplication_x *svcapp = m->serviceapplication;
+  if (!RemoveSymLink(uiapp, context_)) return Status::ERROR;
+  if (!RemoveSymLink(svcapp, context_)) return Status::ERROR;
+
+  return Status::OK;
+}
+
+}  // namespace step
+}  // namespace tpk
diff --git a/src/tpk/step/step_symbolic_link.h b/src/tpk/step/step_symbolic_link.h
new file mode 100644 (file)
index 0000000..cb16c55
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_STEP_STEP_SYMBOLIC_LINK_H_
+#define TPK_STEP_STEP_SYMBOLIC_LINK_H_
+
+#include "common/app_installer.h"
+
+namespace tpk {
+namespace step {
+
+class StepSymbolicLink : public common_installer::Step {
+ public:
+  using Step::Step;
+  Status process() override;
+  Status clean() override;
+  Status undo() override;
+};
+
+}  // namespace step
+}  // namespace tpk
+
+#endif  // TPK_STEP_STEP_SYMBOLIC_LINK_H_
diff --git a/src/tpk/task.cc b/src/tpk/task.cc
new file mode 100644 (file)
index 0000000..bedd1de
--- /dev/null
@@ -0,0 +1,106 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/task.h"
+#ifdef HOSTTEST
+#include "test/mock_pkgmgr_installer.h"
+#else
+#include <pkgmgr_installer.h>
+#include "common/app_installer.h"
+#include "common/step/step_copy.h"
+#include "common/step/step_generate_xml.h"
+#include "common/step/step_parse.h"
+#include "common/step/step_record.h"
+#include "common/step/step_remove.h"
+#include "common/step/step_revoke_security.h"
+#include "common/step/step_security.h"
+#include "common/step/step_signal.h"
+#include "common/step/step_signature.h"
+#include "common/step/step_unregister.h"
+#include "common/step/step_unzip.h"
+#include "tpk/step/step_parse.h"
+#include "tpk/step/step_symbolic_link.h"
+#include "tpk/exception.h"
+#endif
+
+
+namespace ci = common_installer;
+
+namespace {
+  const char kPkgType[] = "tpk";
+}  // namespace
+
+
+namespace tpk {
+
+/* Constructor
+ */
+Task::Task(const int argc, char** argv) {
+  pi_ = pkgmgr_installer_new();
+  if (!pi_) {
+    throw Exception("Not enough memory");
+  }
+  if (!!pkgmgr_installer_receive_request(pi_, argc, argv)) {
+    throw Exception("Invalid Argument");
+  }
+  request_ = pkgmgr_installer_get_request_type(pi_);
+}
+
+
+/* Destructor
+ */
+::tpk::Task::~Task() {
+  if (pi_) {
+    pkgmgr_installer_free(pi_);
+    pi_ = NULL;
+  }
+}
+
+
+void Task::Run(void) {
+  switch (request_) {
+    case PKGMGR_REQ_INSTALL:
+      Install();
+      break;
+    case PKGMGR_REQ_UNINSTALL:
+      Uninstall();
+      break;
+    case PKGMGR_REQ_REINSTALL:
+      Reinstall();
+      break;
+    default:
+      throw Exception("Unsupported request");
+  }
+}
+
+void Task::Install(void) {
+  ci::AppInstaller ai(pi_, kPkgType);
+
+  ai.AddStep<ci::unzip::StepUnzip>();
+  ai.AddStep<ci::signature::StepSignature>();
+  ai.AddStep<tpk::step::StepParse>();
+  ai.AddStep<ci::signal::StepSignal>();
+  ai.AddStep<ci::copy::StepCopy>();
+  ai.AddStep<tpk::step::StepSymbolicLink>();
+  ai.AddStep<ci::security::StepSecurity>();
+  ai.AddStep<ci::generate_xml::StepGenerateXml>();
+  ai.AddStep<ci::record::StepRecord>();
+
+  ai.Run();
+}
+
+void Task::Uninstall(void) {
+  ci::AppInstaller ai(pi_, kPkgType);
+
+  ai.AddStep<ci::parse::StepParse>();
+  ai.AddStep<ci::signal::StepSignal>();
+  ai.AddStep<ci::revoke_security::StepRevokeSecurity>();
+  ai.AddStep<ci::unregister::StepUnregister>();
+  ai.AddStep<ci::remove::StepRemove>();
+
+  ai.Run();
+}
+
+void Task::Reinstall(void) {
+}
+
+}  // namespace tpk
+
diff --git a/src/tpk/task.h b/src/tpk/task.h
new file mode 100644 (file)
index 0000000..2730716
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_TASK_H_
+#define TPK_TASK_H_
+
+#ifdef HOSTTEST
+#include "test/mock_pkgmgr_installer.h"
+#else
+#include <pkgmgr_installer.h>
+#endif
+
+namespace tpk {
+
+class Task {
+ public:
+  Task(int argc, char** argv);
+  ~Task();
+  void Run();
+
+
+ private:
+  void Install();
+  void Uninstall();
+  void Reinstall();
+
+  pkgmgr_installer* pi_;
+  int request_;
+};  //  class Task
+
+}  //  namespace tpk
+#endif  // TPK_TASK_H_
diff --git a/src/tpk/xml_nodes.h b/src/tpk/xml_nodes.h
new file mode 100644 (file)
index 0000000..3a041aa
--- /dev/null
@@ -0,0 +1,224 @@
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_XML_NODES_H_
+#define TPK_XML_NODES_H_
+
+#include <libxml/globals.h>
+#include <libxml/xmlstring.h>
+#include <libxml/xmlreader.h>
+#include <vector>
+#include "tpk/exception.h"
+#include "utils/logging.h"
+
+using std::vector;
+
+namespace tpk {
+
+class InvalidNodeTypeException: public tpk::Exception {};
+class InvalidNodeNameException: public tpk::Exception {};
+
+
+class XmlNode {
+  SCOPE_LOG_TAG(XmlNode)
+
+ public:
+  int depth;
+  int node_type;
+  xmlChar* name;    // The name of node
+  xmlChar* data;    // Internal text of the node
+
+  XmlNode() : name(NULL), data(NULL), depth(-1),
+      node_type(XML_READER_TYPE_NONE) {
+  }
+
+  virtual ~XmlNode() {
+    Free();
+  }
+
+  virtual void ReadBasicValues(xmlTextReaderPtr reader) {
+    depth = xmlTextReaderDepth(reader);
+    node_type = xmlTextReaderNodeType(reader);
+    data = xmlTextReaderReadString(reader);
+  }
+
+  virtual void Init(xmlTextReaderPtr reader) {
+    name = xmlTextReaderName(reader);
+    if (!xmlStrEqual(name, node_name_)) {
+      LOG(ERROR) << "Invalid node!  actual name=" << name
+          << ", expected name=" << node_name_ << std::endl;
+      xmlFree(name);
+      throw InvalidNodeNameException();
+    }
+    ReadBasicValues(reader);
+  }
+
+  virtual void Free() {
+    xmlFree(name);
+    xmlFree(data);
+  }
+
+  virtual void SetExpectedNodeName(const char* nodeName) {
+    node_name_ = const_cast<xmlChar*>(
+        reinterpret_cast<const xmlChar*>(nodeName));
+  }
+
+
+ private:
+  xmlChar* node_name_;
+};
+
+
+class XmlNodeIcon : public XmlNode {
+ public:
+  XmlNodeIcon() {
+    XmlNode::SetExpectedNodeName("icon");
+  }
+
+  virtual void Init(xmlTextReaderPtr reader) {
+    XmlNode::Init(reader);
+  }
+};
+
+
+class XmlNodeLabel : public XmlNode {
+ public:
+  XmlNodeLabel() {
+    XmlNode::SetExpectedNodeName("label");
+  }
+  virtual void Init(xmlTextReaderPtr reader) {
+    XmlNode::Init(reader);
+  }
+};
+
+class XmlNodeProfile : public XmlNode {
+ public:
+  XmlNodeProfile() {
+    XmlNode::SetExpectedNodeName("profile");
+  }
+
+  virtual void Init(xmlTextReaderPtr reader) {
+    XmlNode::Init(reader);
+  }
+};
+
+class XmlNodeUiApplication : public XmlNode {
+ public:
+  xmlChar *appid;
+  xmlChar *exec;
+  xmlChar *type;
+  xmlChar *multiple;
+  xmlChar *taskmanage;
+  xmlChar *nodisplay;
+
+  XmlNodeIcon icon;
+  XmlNodeLabel label;
+
+  XmlNodeUiApplication() : appid(NULL), exec(NULL), type(NULL),
+      multiple(NULL), taskmanage(NULL), nodisplay(NULL) {
+    XmlNode::SetExpectedNodeName("ui-application");
+  }
+
+  void Init(xmlTextReaderPtr reader) {
+    XmlNode::Init(reader);
+
+    appid = xmlTextReaderGetAttribute(reader,
+        const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("appid")));
+    exec = xmlTextReaderGetAttribute(reader,
+        const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("exec")));
+    type = xmlTextReaderGetAttribute(reader,
+        const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("type")));
+    multiple = xmlTextReaderGetAttribute(reader,
+        const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("multiple")));
+    taskmanage = xmlTextReaderGetAttribute(reader,
+        const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("taskmanage")));
+    nodisplay = xmlTextReaderGetAttribute(reader,
+        const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("nodisplay")));
+  }
+  virtual ~XmlNodeUiApplication() {
+    xmlFree(appid);
+    xmlFree(exec);
+    xmlFree(type);
+    xmlFree(multiple);
+    xmlFree(taskmanage);
+    xmlFree(nodisplay);
+  }
+};
+
+
+class XmlNodePrivilege : public XmlNode {
+ public:
+  XmlNodePrivilege() {
+    XmlNode::SetExpectedNodeName("privilege");
+  }
+  virtual void Init(xmlTextReaderPtr reader) {
+    XmlNode::Init(reader);
+  }
+};
+
+class XmlNodePrivileges: public XmlNode {
+ public:
+  vector<XmlNodePrivilege *> v_privilege;
+
+  XmlNodePrivileges() {
+    XmlNode::SetExpectedNodeName("privileges");
+  }
+  ~XmlNodePrivileges() {
+    // clear v_privilege
+    vector<XmlNodePrivilege *>::iterator it;
+    for (auto& ptr : v_privilege) {
+      delete ptr;
+    }
+  }
+  virtual void Init(xmlTextReaderPtr reader) {
+    XmlNode::Init(reader);
+  }
+  virtual void addPrivilege(xmlTextReaderPtr reader) {
+    if (xmlStrEqual(xmlTextReaderConstName(reader),
+          reinterpret_cast<const xmlChar *>("privilege"))) {
+      XmlNodePrivilege *p = new XmlNodePrivilege();
+      p->Init(reader);
+      v_privilege.push_back(p);
+    }
+  }
+  vector<XmlNodePrivilege *> getPrivilegeVector(void) {
+    return v_privilege;
+  }
+};
+
+class XmlNodeManifest : public XmlNode {
+ public:
+  xmlChar *xmlns;
+  xmlChar *api_version;
+  xmlChar *package;
+  xmlChar *version;
+  XmlNodeProfile profile;
+  XmlNodeUiApplication ui_application;
+  XmlNodePrivileges privileges;
+
+  XmlNodeManifest() : xmlns(NULL), api_version(NULL), package(NULL),
+      version(NULL) {
+    XmlNode::SetExpectedNodeName("manifest");
+  }
+
+  void Init(xmlTextReaderPtr reader) {
+    XmlNode::Init(reader);
+
+    xmlns = xmlTextReaderGetAttribute(reader,
+        reinterpret_cast<const xmlChar*>("xmlns"));
+    api_version = xmlTextReaderGetAttribute(reader,
+        reinterpret_cast<const xmlChar*>("api-version"));
+    package = xmlTextReaderGetAttribute(reader,
+        reinterpret_cast<const xmlChar*>("package"));
+    version = xmlTextReaderGetAttribute(reader,
+        reinterpret_cast<const xmlChar*>("version"));
+  }
+
+  ~XmlNodeManifest() {
+    xmlFree(xmlns);
+    xmlFree(api_version);
+    xmlFree(package);
+    xmlFree(version);
+  }
+};
+
+}  // namespace tpk
+#endif  // TPK_XML_NODES_H_