Allow optional elements in tpk manifest xml 11/36911/4
authorYoumin Ha <youmin.ha@samsung.com>
Tue, 17 Mar 2015 04:47:33 +0000 (13:47 +0900)
committerYoumin Ha <youmin.ha@samsung.com>
Fri, 20 Mar 2015 00:35:55 +0000 (09:35 +0900)
Some xml elements are optional, thus they can be omitted in the
tizen-manifest.xml.
This patch allows those elements to be omitted.
In addition, null checking routine in common/step/step_generate_xml.cc
is added, because if there is no description in tizen-manifest.xml,
manifest_x->description will be nullptr.

Change-Id: Ie37236b472011c9d516840cc9cda86b777a6a474
Signed-Off-By: Youmin Ha <youmin.ha@samsung.com>
src/common/step/step_generate_xml.cc
src/tpk/step/step_parse.cc
src/tpk/step/step_parse.h
src/tpk/step/step_symbolic_link.cc
src/tpk/task.cc
src/tpk/task.h

index c0f3df5..351b95d 100644 (file)
@@ -73,7 +73,8 @@ Step::Status StepGenerateXml::process() {
   xmlTextWriterWriteAttribute(writer, BAD_CAST "version",
       BAD_CAST context_->manifest_data()->version);
 
-  if ( context_->manifest_data()->description->name )
+  if ( context_->manifest_data()->description &&
+      context_->manifest_data()->description->name )
     xmlTextWriterWriteFormatElement(writer, BAD_CAST "description",
         "%s", BAD_CAST context_->manifest_data()->description->name);
   else
@@ -114,7 +115,7 @@ Step::Status StepGenerateXml::process() {
 
     fs::path icon = fs::path(ui->appid) += fs::path(".png");
 
-    if (ui->icon->name) {
+    if (ui->icon && ui->icon->name) {
       fs::path app_icon = fs::path(context_->pkg_path()) / fs::path(ui->appid)
         / fs::path(ui->icon->name);
       if (fs::exists(app_icon))
@@ -132,20 +133,24 @@ Step::Status StepGenerateXml::process() {
     for (; appc_ui != nullptr; appc_ui = appc_ui->next) {
       xmlTextWriterStartElement(writer, BAD_CAST "app-control");
 
-      xmlTextWriterStartElement(writer, BAD_CAST "operation");
-      xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
-          BAD_CAST appc_ui->operation->name);
-      xmlTextWriterEndElement(writer);
-
-      xmlTextWriterStartElement(writer, BAD_CAST "uri");
-      xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
-          BAD_CAST appc_ui->uri->name);
-      xmlTextWriterEndElement(writer);
-
-      xmlTextWriterStartElement(writer, BAD_CAST "mime");
-      xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
-          BAD_CAST appc_ui->mime->name);
-      xmlTextWriterEndElement(writer);
+      if (appc_ui->operation) {
+        xmlTextWriterStartElement(writer, BAD_CAST "operation");
+        xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
+            BAD_CAST appc_ui->operation->name);
+        xmlTextWriterEndElement(writer);
+      }
+      if (appc_ui->uri) {
+        xmlTextWriterStartElement(writer, BAD_CAST "uri");
+        xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
+            BAD_CAST appc_ui->uri->name);
+        xmlTextWriterEndElement(writer);
+      }
+      if (appc_ui->mime) {
+        xmlTextWriterStartElement(writer, BAD_CAST "mime");
+        xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
+            BAD_CAST appc_ui->mime->name);
+        xmlTextWriterEndElement(writer);
+      }
 
       xmlTextWriterEndElement(writer);
     }
@@ -168,9 +173,10 @@ Step::Status StepGenerateXml::process() {
         BAD_CAST exec_path.string().c_str());
     xmlTextWriterWriteAttribute(writer, BAD_CAST "type",
         BAD_CAST svc->type);
-
-    xmlTextWriterWriteFormatElement(writer, BAD_CAST "label",
-        "%s", BAD_CAST svc->label->name);
+    if (svc->label) {
+      xmlTextWriterWriteFormatElement(writer, BAD_CAST "label",
+          "%s", BAD_CAST svc->label->name);
+    }
 
     // the icon is renamed to <appid.png>
     // and located in TZ_USER_ICON/TZ_SYS_ICON
@@ -179,7 +185,7 @@ Step::Status StepGenerateXml::process() {
     utils::CreateDir(icon_path_);
     fs::path icon = fs::path(svc->appid) += fs::path(".png");
 
-    if (svc->icon->name) {
+    if (svc->icon && svc->icon->name) {
       fs::path app_icon = fs::path(context_->pkg_path()) / fs::path(svc->appid)
           / fs::path(svc->icon->name);
       if (fs::exists(app_icon))
@@ -194,20 +200,24 @@ Step::Status StepGenerateXml::process() {
     for (; appc_svc != nullptr; appc_svc = appc_svc->next) {
       xmlTextWriterStartElement(writer, BAD_CAST "app-control");
 
-      xmlTextWriterStartElement(writer, BAD_CAST "operation");
-      xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
-          BAD_CAST appc_svc->operation->name);
-      xmlTextWriterEndElement(writer);
-
-      xmlTextWriterStartElement(writer, BAD_CAST "uri");
-      xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
-          BAD_CAST appc_svc->uri->name);
-      xmlTextWriterEndElement(writer);
-
-      xmlTextWriterStartElement(writer, BAD_CAST "mime");
-      xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
-          BAD_CAST appc_svc->mime->name);
-      xmlTextWriterEndElement(writer);
+      if (appc_svc->operation) {
+        xmlTextWriterStartElement(writer, BAD_CAST "operation");
+        xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
+            BAD_CAST appc_svc->operation->name);
+        xmlTextWriterEndElement(writer);
+      }
+      if (appc_svc->uri) {
+        xmlTextWriterStartElement(writer, BAD_CAST "uri");
+        xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
+            BAD_CAST appc_svc->uri->name);
+        xmlTextWriterEndElement(writer);
+      }
+      if (appc_svc->mime) {
+        xmlTextWriterStartElement(writer, BAD_CAST "mime");
+        xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
+            BAD_CAST appc_svc->mime->name);
+        xmlTextWriterEndElement(writer);
+      }
 
       xmlTextWriterEndElement(writer);
     }
index 85de2f7..830c882 100644 (file)
@@ -26,13 +26,22 @@ namespace {
       XmlElement* parent, const string element_name) {
     vector<XmlElement*> v = tree->Children(parent, element_name);
     if (v.size() < 1) {
-      LOG(ERROR) << element_name << " is not found as a child of " <<
+      LOG(INFO) << element_name << " is not found as a child of " <<
           parent->name();
       return nullptr;
     }
     return v[0];  // Always return only the 1st child
   }
 
+  const char* string_strdup(const string &s) {
+    static const string nullstr = XmlElement::null_string();
+    if (s == XmlElement::null_string()) {
+      LOG(DEBUG) << "it is null_string";
+      return nullptr;
+    }
+    return strdup(s.c_str());
+  }
+
 
 }  // namespace
 
@@ -52,6 +61,7 @@ Status StepParse::process() {
   if (!mPath) {
     return Status::ERROR;
   }
+  LOG(INFO) << "Parse " << mPath->c_str();
 
   XmlParser parser;
   std::unique_ptr<XmlTree> tree(parser.ParseAndGetNewTree(mPath->c_str()));
@@ -90,7 +100,10 @@ bool StepParse::SetContextByManifestParser(XmlTree* tree) {
       * ui_application, * label;
 
   // manifest
-  if (nullptr == (manifest = tree->GetRootElement())) return false;
+  if (nullptr == (manifest = tree->GetRootElement())) {
+    LOG(ERROR) << "No mandatory manifest element in xml";
+    return false;
+  }
 
   LOG(DEBUG) << "Getting manifest xml data";
   LOG(DEBUG) << "manifest: xmlns='" << manifest->attr("xmlns") <<
@@ -100,86 +113,110 @@ bool StepParse::SetContextByManifestParser(XmlTree* tree) {
 
   // ui_application
   if (nullptr == (ui_application = Get1stChild(tree,
-          manifest, "ui-application"))) return false;
-  if (nullptr == (label = Get1stChild(tree, ui_application, "label")))
+          manifest, "ui-application"))) {
+    LOG(ERROR) << "No mandatory ui-application element in manifest xml";
     return false;
+  }
+  if (nullptr == (label = Get1stChild(tree, ui_application, "label"))) {
+    LOG(ERROR) << "No mandatory label element in manifest xml";
+    return false;
+  }
 
   // set context_
   context_->config_data()->set_application_name(label->content());
   context_->config_data()->set_required_version(manifest->attr("api_version"));
   context_->set_pkgid(manifest->attr("package"));
+  context_->set_manifest(static_cast<manifest_x*>(
+      calloc(1, sizeof(manifest_x))));
 
   // set context_->manifest_data()
   return SetPkgInfoManifest(context_->manifest_data(), tree, manifest);
 }
 
+
 bool StepParse::SetPkgInfoManifest(manifest_x* m,
     XmlTree* tree,
     XmlElement* manifest) {
+
   // Get required elements
-  XmlElement* ui_application, * label, * icon, * description;
-  if (nullptr == (ui_application = Get1stChild(tree,
-          manifest, "ui-application"))) return false;
-  if (nullptr == (label = Get1stChild(tree, ui_application, "label")))
-    return false;
-  if (nullptr == (icon = Get1stChild(tree, ui_application, "icon")))
+  XmlElement* ui_application = Get1stChild(tree, manifest, "ui-application");
+  if (!ui_application) {
+    LOG(ERROR) << "No mandatory ui-application element in manifest xml";
     return false;
-  if (nullptr == (description = Get1stChild(tree,
-          ui_application, "description"))) return false;
-
-  // 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(manifest->attr("package").c_str());
+  }
+
+  // manifest's attribute
+  m->package = string_strdup(manifest->attr("package"));
   m->type = strdup("tpk");
-  m->version = strdup(manifest->attr("version").c_str());
-  m->label->name = strdup(label->content().c_str());
-  m->description->name = strdup(description->content().c_str());
-  m->mainapp_id = strdup(ui_application->attr("appid").c_str());
+  m->version = string_strdup(manifest->attr("version"));
+  m->mainapp_id = string_strdup(ui_application->attr("appid"));
+
+  // manifest' attribute from children's values
+  XmlElement* label = Get1stChild(tree, ui_application, "label");
+  if (label) {
+    m->label =  static_cast<label_x*>(calloc(1, sizeof(label_x)));
+    m->label->name = string_strdup(label->content());
+  }
+  XmlElement* description = Get1stChild(tree, manifest, "description");
+  if (description) {
+    m->description =  static_cast<description_x*>
+      (calloc(1, sizeof(description_x)));
+    m->description->name = string_strdup(description->content());
+  }
+
+  // Set children elements
+  return SetPkgInfoChildren(m, tree, manifest);
+}
+
+bool StepParse::SetPkgInfoChildren(manifest_x *m,
+    XmlTree *tree, XmlElement* manifest) {
 
   // Privileges
-  XmlElement* privileges;
-  if (nullptr == (privileges = Get1stChild(tree, manifest, "privileges"))) {
-    return false;
-  }
-  vector<XmlElement*> v_priv = tree->Children(privileges, "privilege");
-  for (auto& privilege : v_priv) {
-    privilege_x *p =
-        static_cast<privilege_x *>(calloc(1, sizeof(privilege_x)));
-    // privilege data text
-    p->text = strdup(privilege->content().c_str());
-    LISTADD(m->privileges->privilege, p);
-    LOG(INFO) << "Add a privilege: " << p->text;
+  XmlElement* privileges = Get1stChild(tree, manifest, "privileges");
+  if (privileges) {
+    m->privileges = static_cast<privileges_x*>
+        (calloc(1, sizeof(privileges_x)));
+
+    vector<XmlElement*> v_priv = tree->Children(privileges, "privilege");
+    for (auto& privilege : v_priv) {
+      privilege_x *p =
+          static_cast<privilege_x *>(calloc(1, sizeof(privilege_x)));
+      // privilege data text
+      p->text = string_strdup(privilege->content());
+      LISTADD(m->privileges->privilege, p);
+      LOG(INFO) << "Add a privilege: " << p->text;
+    }
   }
 
-  // Other app data (null initialization)
+  // service-application
   m->serviceapplication = nullptr;  // NOTE: 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(ui_application->attr("appid").c_str());
-  m->uiapplication->exec = strdup(ui_application->attr("exec").c_str());
-  m->uiapplication->type = strdup(ui_application->attr("type").c_str());
-
-  m->uiapplication->label->name = strdup(label->content().c_str());
-  m->uiapplication->icon->name = strdup(icon->content().c_str());
-  m->uiapplication->next = nullptr;
 
+  // ui-application
+  XmlElement* ui_application = Get1stChild(tree, manifest, "ui-application");
+  if (ui_application) {
+    m->uiapplication = static_cast<uiapplication_x*>
+      (calloc (1, sizeof(uiapplication_x)));
+
+    m->uiapplication->appid = string_strdup(ui_application->attr("appid"));
+    m->uiapplication->exec = string_strdup(ui_application->attr("exec"));
+    m->uiapplication->type = string_strdup(ui_application->attr("type"));
+
+    LOG(DEBUG) << "appid=" << m->uiapplication->appid <<
+        ", exec=" << m->uiapplication->exec <<
+        ", type=" << m->uiapplication->type;
+    XmlElement* label = Get1stChild(tree, ui_application, "label");
+    if (label) {
+      m->uiapplication->label = static_cast<label_x*>
+          (calloc(1, sizeof(label_x)));
+      m->uiapplication->label->name = string_strdup(label->content());
+    }
+    XmlElement* icon = Get1stChild(tree, ui_application, "icon");
+    if (icon) {
+      m->uiapplication->icon = static_cast<icon_x*>
+          (calloc(1, sizeof(icon_x)));
+      m->uiapplication->icon->name = string_strdup(icon->content());
+    }
+  }
   return true;
 }
 
index 84e48cb..f0c2017 100644 (file)
@@ -23,8 +23,9 @@ class StepParse : public common_installer::Step {
       const boost::filesystem::path& dir);
   bool SetContextByManifestParser(xml_parser::XmlTree* tree);
   bool SetPkgInfoManifest(manifest_x* m,
-      xml_parser::XmlTree* tree,
-      xml_parser::XmlElement* manifest);
+      xml_parser::XmlTree* tree, xml_parser::XmlElement* manifest);
+  bool SetPkgInfoChildren(manifest_x *m,
+      xml_parser::XmlTree *tree, xml_parser::XmlElement* manifest);
 };
 
 }  // namespace step
index 5e2f61b..38f1181 100644 (file)
@@ -35,7 +35,7 @@ bool CreateSymLink(T *app, ContextInstaller* context) {
 
     // 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 " <<
+    LOG(INFO) << "Creating symlink " << symlink_path << " pointing " <<
         app->exec;
     fs::create_symlink(fs::path(app->exec), symlink_path, error);
     if (error) {
@@ -90,9 +90,9 @@ Status StepSymbolicLink::process() {
     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;
 }
 
index 892c043..53db317 100644 (file)
@@ -69,7 +69,7 @@ bool Task::Init(int argc, char** argv) {
 
 
 bool Task::Run() {
-  bool ret = false;
+  int ret = 0;
   switch (request_) {
     case PKGMGR_REQ_INSTALL:
       ret = Install();
@@ -81,10 +81,14 @@ bool Task::Run() {
       ret = Reinstall();
       break;
   }
-  return ret;
+  if (ret != 0) {
+    LOG(ERROR) << "Got error from AppInstaler: error code " << ret;
+    return false;
+  }
+  return true;
 }
 
-bool Task::Install() {
+int Task::Install() {
   ci::AppInstaller ai(pi_, kPkgType);
 
   ai.AddStep<ci::unzip::StepUnzip>();
@@ -100,7 +104,7 @@ bool Task::Install() {
   return ai.Run();
 }
 
-bool Task::Uninstall() {
+int Task::Uninstall() {
   ci::AppInstaller ai(pi_, kPkgType);
 
   ai.AddStep<ci::parse::StepParse>();
@@ -112,8 +116,8 @@ bool Task::Uninstall() {
   return ai.Run();
 }
 
-bool Task::Reinstall() {
-  return false;
+int Task::Reinstall() {
+  return 0;
 }
 
 }  // namespace tpk
index 8af9e0f..cb71c40 100644 (file)
@@ -19,9 +19,9 @@ class Task {
 
 
  private:
-  bool Install();
-  bool Uninstall();
-  bool Reinstall();
+  int Install();
+  int Uninstall();
+  int Reinstall();
 
   pkgmgr_installer* pi_;
   int request_;