2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file task_manifest_file.cpp
18 * @author Pawel Sikorski (p.sikorski@samgsung.com)
25 #include <dpl/assert.h>
31 #include <widget_install/task_manifest_file.h>
32 #include <widget_install/job_widget_install.h>
33 #include <widget_install/widget_install_errors.h>
34 #include <widget_install/widget_install_context.h>
35 #include <dpl/wrt-dao-ro/global_config.h>
36 #include <dpl/log/log.h>
37 #include <dpl/file_input.h>
38 #include <dpl/file_output.h>
40 #include <dpl/exception.h>
41 #include <dpl/foreach.h>
42 #include <dpl/sstream.h>
43 #include <dpl/string.h>
44 #include <dpl/optional.h>
45 #include <dpl/utils/wrt_utility.h>
47 #include <libxml_utils.h>
48 #include <pkgmgr/pkgmgr_parser.h>
50 #define DEFAULT_ICON_NAME "icon.png"
52 using namespace WrtDB;
55 typedef std::map<DPL::String, DPL::String> LanguageTagMap;
57 LanguageTagMap getLanguageTagMap()
61 #define ADD(tag, l_tag) map.insert(std::make_pair(L ## # tag, L ## # l_tag));
62 #include "languages.def"
68 DPL::OptionalString getLangTag(const DPL::String& tag)
70 static LanguageTagMap TagsMap =
73 DPL::String langTag = tag;
75 LogDebug("Trying to map language tag: " << langTag);
76 size_t pos = langTag.find_first_of(L'_');
77 if (pos != DPL::String::npos) {
80 DPL::OptionalString ret;
82 LanguageTagMap::iterator it = TagsMap.find(langTag);
83 if (it != TagsMap.end()) {
86 LogDebug("Mapping IANA Language tag to language tag: " <<
87 langTag << " -> " << ret);
94 namespace WidgetInstall {
96 const char * TaskManifestFile::encoding = "UTF-8";
98 TaskManifestFile::TaskManifestFile(InstallerContext &inCont) :
99 DPL::TaskDecl<TaskManifestFile>(this),
102 if (false == m_context.existingWidgetInfo.isExist) {
103 AddStep(&TaskManifestFile::stepCopyIconFiles);
104 AddStep(&TaskManifestFile::stepCreateExecFile);
105 AddStep(&TaskManifestFile::stepGenerateManifest);
106 AddStep(&TaskManifestFile::stepParseManifest);
107 AddStep(&TaskManifestFile::stepFinalize);
109 // for widget update.
110 AddStep(&TaskManifestFile::stepBackupIconFiles);
111 AddStep(&TaskManifestFile::stepCopyIconFiles);
112 AddStep(&TaskManifestFile::stepGenerateManifest);
113 AddStep(&TaskManifestFile::stepParseUpgradedManifest);
114 AddStep(&TaskManifestFile::stepUpdateFinalize);
116 AddAbortStep(&TaskManifestFile::stepAbortIconFiles);
120 TaskManifestFile::~TaskManifestFile()
124 void TaskManifestFile::stepCreateExecFile()
126 //ln -s /usr/bin/wrt-client {widget-handle}
128 std::ostringstream real_path;
129 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
130 if (pkgname.IsNull()) {
131 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
134 real_path << m_context.locations->getBinaryDir() << "/" << m_context.widgetHandle;
135 std::string clientExeStr = GlobalConfig::GetWrtClientExec();
137 LogInfo("link -s " << clientExeStr << " " << real_path.str());
138 symlink(clientExeStr.c_str(), real_path.str().c_str());
140 m_context.job->UpdateProgress(
141 InstallerContext::INSTALL_CREATE_EXECFILE,
142 "Widget execfile creation Finished");
145 void TaskManifestFile::stepCopyIconFiles()
147 LogDebug("CopyIconFiles");
149 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
150 if (pkgname.IsNull()) {
151 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
153 Assert(!!m_context.widgetHandle);
155 WidgetDAOReadOnly dao(*m_context.widgetHandle);
156 WidgetDAOReadOnly::WidgetLocalizedIconList locList = dao.getLocalizedIconList();
157 WidgetDAOReadOnly::WidgetIconList list = dao.getIconList();
161 DPL::String i = it->widgetLocale;
162 DPL::OptionalString src;
165 if (icon->iconId == it->iconId) {
169 LogDebug("Icon for locale: " << i << "is : " << src);
171 std::ostringstream sourceFile;
172 std::ostringstream targetFile;
176 sourceFile << m_context.locations->getSourceDir() << "/";
179 sourceFile << "locales/" << i << "/";
184 targetFile << GlobalConfig::GetUserWidgetDesktopIconPath() << "/";
185 targetFile << getIconTargetFilename(i);
187 if (m_context.locations->browserRequest())
189 m_context.locations->setIconTargetFilenameForLocale(targetFile.str());
193 //Use WRT default (not from the widget) only if widget default (not
194 // localized) doesn't exist.
196 LogError("Using Default Icon for widget");
197 sourceFile << GlobalConfig::GetUserWidgetDefaultIconFile();
203 LogDebug("Copying icon: " << sourceFile.str() <<
204 " -> " << targetFile.str());
206 icon_list.push_back(targetFile.str());
210 DPL::FileInput input(sourceFile.str());
211 DPL::FileOutput output(targetFile.str());
212 DPL::Copy(&input, &output);
215 Catch(DPL::FileInput::Exception::Base)
217 // Error while opening or closing source file
218 //ReThrowMsg(InstallerException::CopyIconFailed, sourceFile.str());
220 "Copying widget's icon failed. Widget's icon will not be"\
221 "available from Main Screen");
224 Catch(DPL::FileOutput::Exception::Base)
226 // Error while opening or closing target file
227 //ReThrowMsg(InstallerException::CopyIconFailed, targetFile.str());
229 "Copying widget's icon failed. Widget's icon will not be"\
230 "available from Main Screen");
233 Catch(DPL::CopyFailed)
235 // Error while copying
236 //ReThrowMsg(InstallerException::CopyIconFailed, targetFile.str());
238 "Copying widget's icon failed. Widget's icon will not be"\
239 "available from Main Screen");
243 m_context.job->UpdateProgress(
244 InstallerContext::INSTALL_COPY_ICONFILE,
245 "Widget iconfile copy Finished");
248 void TaskManifestFile::stepBackupIconFiles()
250 LogDebug("Backup Icon Files");
252 backup_dir << m_context.locations->getPackageInstallationDir();
253 backup_dir << "/" << "backup" << "/";
257 m_context.job->UpdateProgress(
258 InstallerContext::INSTALL_BACKUP_ICONFILE,
259 "New Widget icon file backup Finished");
262 void TaskManifestFile::stepAbortIconFiles()
264 LogDebug("Abrot Icon Files");
265 FOREACH(it, icon_list)
267 LogDebug("Remove Update Icon : " << (*it));
268 unlink((*it).c_str());
271 std::ostringstream b_icon_dir;
272 b_icon_dir << backup_dir.str() << "icons";
274 std::list<std::string> fileList;
275 getFileList(b_icon_dir.str().c_str(), fileList);
277 FOREACH(back_icon, fileList)
279 std::ostringstream res_file;
280 res_file << GlobalConfig::GetUserWidgetDesktopIconPath();
281 res_file << "/" << (*back_icon);
283 std::ostringstream backup_file;
284 backup_file << b_icon_dir.str() << "/" << (*back_icon);
288 DPL::FileInput input(backup_file.str());
289 DPL::FileOutput output(res_file.str());
290 DPL::Copy(&input, &output);
292 Catch(DPL::FileInput::Exception::Base)
294 LogError("Restoration icon File Failed." << backup_file.str()
295 << " to " << res_file.str());
298 Catch(DPL::FileOutput::Exception::Base)
300 LogError("Restoration icon File Failed." << backup_file.str()
301 << " to " << res_file.str());
303 Catch(DPL::CopyFailed)
305 LogError("Restoration icon File Failed." << backup_file.str()
306 << " to " << res_file.str());
311 void TaskManifestFile::stepUpdateFinalize()
313 LogDebug("Finished Update Desktopfile");
316 DPL::String TaskManifestFile::getIconTargetFilename(
317 const DPL::String& languageTag) const
319 DPL::OStringStream filename;
320 DPL::Optional<DPL::String> pkgname = m_context.widgetConfig.pkgname;
321 if (pkgname.IsNull()) {
322 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
325 filename << DPL::ToUTF8String(*pkgname).c_str();
327 if (!languageTag.empty()) {
328 DPL::OptionalString tag = getLangTag(languageTag); // translate en -> en_US etc
329 if (tag.IsNull()) { tag = languageTag; }
331 LocalizationUtils::BCP47LanguageTagToLocale(*tag);
334 filename << L"." << languageTag;
336 filename << L"." << locale;
341 return filename.str();
344 void TaskManifestFile::stepFinalize()
346 LogInfo("Finished ManifestFile step");
350 void TaskManifestFile::saveLocalizedKey(std::ofstream &file,
351 const DPL::String& key,
352 const DPL::String& languageTag)
355 LocalizationUtils::BCP47LanguageTagToLocale(languageTag);
358 if (!locale.empty()) {
359 file << "[" << locale << "]";
364 void TaskManifestFile::updateAilInfo()
366 // Update ail for desktop
367 std::string cfgPkgname =
368 DPL::ToUTF8String(*m_context.widgetConfig.pkgname);
369 const char* pkgname = cfgPkgname.c_str();
371 LogDebug("Update ail desktop : " << pkgname );
372 ail_appinfo_h ai = NULL;
375 ret = ail_package_get_appinfo(pkgname, &ai);
377 ail_package_destroy_appinfo(ai);
380 if (AIL_ERROR_NO_DATA == ret) {
381 if (ail_desktop_add(pkgname) < 0) {
382 LogDebug("Failed to add ail desktop : " << pkgname);
384 } else if (AIL_ERROR_OK == ret) {
385 if (ail_desktop_update(pkgname) < 0) {
386 LogDebug("Failed to update ail desktop : " << pkgname);
391 void TaskManifestFile::backupIconFiles()
393 LogInfo("Backup Icon Files");
395 std::ostringstream b_icon_dir;
396 b_icon_dir << backup_dir.str() << "icons";
398 LogDebug("Create icon backup folder : " << b_icon_dir.str());
399 _WrtMakeDir(b_icon_dir.str().c_str(), 0755, WRT_FILEUTILS_RECUR);
401 std::list<std::string> fileList;
402 getFileList(GlobalConfig::GetUserWidgetDesktopIconPath(), fileList);
403 std::string pkgname = DPL::ToUTF8String(*m_context.widgetConfig.pkgname);
405 FOREACH(it, fileList)
407 if (0 == (strncmp((*it).c_str(), pkgname.c_str(),
408 strlen(pkgname.c_str())))) {
409 std::ostringstream icon_file, backup_icon;
410 icon_file << GlobalConfig::GetUserWidgetDesktopIconPath();
411 icon_file << "/" << (*it);
413 backup_icon << b_icon_dir.str() << "/" << (*it);
415 LogDebug("Backup icon file " << icon_file.str() << " to " <<
419 DPL::FileInput input(icon_file.str());
420 DPL::FileOutput output(backup_icon.str());
421 DPL::Copy(&input, &output);
423 Catch(DPL::FileInput::Exception::Base)
425 LogError("Backup Desktop File Failed.");
426 ReThrowMsg(Exceptions::BackupFailed, icon_file.str());
429 Catch(DPL::FileOutput::Exception::Base)
431 LogError("Backup Desktop File Failed.");
432 ReThrowMsg(Exceptions::BackupFailed, backup_icon.str());
434 Catch(DPL::CopyFailed)
436 LogError("Backup Desktop File Failed.");
437 ReThrowMsg(Exceptions::BackupFailed, backup_icon.str());
439 unlink((*it).c_str());
444 void TaskManifestFile::getFileList(const char* path,
445 std::list<std::string> &list)
447 DIR* dir = opendir(path);
449 LogError("icon directory doesn't exist");
450 ThrowMsg(Exceptions::InternalError, path);
453 struct dirent* d_ent;
455 if ((d_ent = readdir(dir))) {
456 if(strcmp(d_ent->d_name, ".") == 0 ||
457 strcmp(d_ent->d_name, "..") == 0) {
460 std::string file_name = d_ent->d_name;
461 list.push_back(file_name);
466 void TaskManifestFile::stepGenerateManifest()
468 DPL::String pkgname = *m_context.widgetConfig.pkgname;
469 manifest_name = pkgname + L".xml";
470 manifest_file += L"/tmp/" + manifest_name;
472 //libxml - init and check
473 LibxmlSingleton::Instance().init();
475 writeManifest(manifest_file);
479 m_context.job->UpdateProgress(
480 InstallerContext::INSTALL_CREATE_MANIFEST,
481 "Widget Manifest Creation Finished");
484 void TaskManifestFile::stepParseManifest()
486 int code = pkgmgr_parser_parse_manifest_for_installation(
487 DPL::ToUTF8String(manifest_file).c_str(), NULL);
491 LogError("Manifest parser error: " << code);
492 ThrowMsg(ManifestParsingError, "Parser returncode: " << code);
495 // TODO : It will be removed. AIL update is temporary code request by pkgmgr team.
498 m_context.job->UpdateProgress(
499 InstallerContext::INSTALL_CREATE_MANIFEST,
500 "Widget Manifest Parsing Finished");
501 LogDebug("Manifest parsed");
504 void TaskManifestFile::stepParseUpgradedManifest()
506 int code = pkgmgr_parser_parse_manifest_for_upgrade(
507 DPL::ToUTF8String(manifest_file).c_str(), NULL);
511 LogError("Manifest parser error: " << code);
512 ThrowMsg(ManifestParsingError, "Parser returncode: " << code);
515 // TODO : It will be removed. AIL update is temporary code request by pkgmgr team.
518 m_context.job->UpdateProgress(
519 InstallerContext::INSTALL_CREATE_MANIFEST,
520 "Widget Manifest Parsing Finished");
521 LogDebug("Manifest parsed");
524 void TaskManifestFile::validateManifest()
526 int code = pkgmgr_parser_check_manifest_validation(
527 DPL::ToUTF8String(manifest_name).c_str());
531 LogError("Manifest validation error");
532 //TODO: manifest files are not yet validating properly because of href
533 // attribute in author element (incompatible types in W3C spec. and
535 //ThrowMsg(ManifestValidationError, "Validation returncode: " << code);
538 m_context.job->UpdateProgress(
539 InstallerContext::INSTALL_CREATE_MANIFEST,
540 "Widget Manifest Validation Finished");
541 LogDebug("Manifest validated");
544 void TaskManifestFile::commitManifest()
546 LogDebug("Commiting manifest file : " << manifest_file);
548 std::ostringstream destFile;
549 destFile << "/opt/share/packages" << "/"; //TODO constant with path
550 destFile << DPL::ToUTF8String(manifest_name);
551 LogInfo("cp " << manifest_file << " " << destFile.str());
553 DPL::FileInput input(DPL::ToUTF8String(manifest_file));
554 DPL::FileOutput output(destFile.str());
555 DPL::Copy(&input, &output);
556 LogDebug("Manifest writen to: " << destFile.str());
559 unlink((DPL::ToUTF8String(manifest_file)).c_str());
560 manifest_file = DPL::FromUTF8String(destFile.str().c_str());
563 void TaskManifestFile::writeManifest(const DPL::String & path)
565 LogDebug("Generating manifest file : " << path);
569 setWidgetExecPath(uiApp);
570 setWidgetName(manifest, uiApp);
571 setWidgetIcons(uiApp);
572 setWidgetManifest(manifest);
573 setWidgetOtherInfo(uiApp);
574 setAppServiceInfo(uiApp);
576 manifest.addUiApplication(uiApp);
577 manifest.generate(path);
578 LogDebug("Manifest file serialized");
581 void TaskManifestFile::setWidgetExecPath(UiApplication & uiApp)
583 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
584 if (pkgname.IsNull()) {
585 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
588 std::ostringstream path;
589 path << m_context.locations->getBinaryDir() << "/" << *m_context.widgetHandle;
590 uiApp.setExec(DPL::FromASCIIString(path.str()));
593 void TaskManifestFile::setWidgetName(Manifest & manifest, UiApplication & uiApp)
595 Assert(!!m_context.widgetHandle);
596 WidgetDAOReadOnly dao(*m_context.widgetHandle);
597 LanguageTagsList languageTags(dao.getLanguageTags());
598 bool defaultNameSaved = false;
601 FOREACH(i, languageTags)
603 DPL::OptionalString tag = getLangTag(*i); // translate en -> en_US etc
608 DPL::OptionalString name = dao.getLocalizedInfo(*i).name;
609 generateWidgetName(manifest, uiApp, tag, name, defaultNameSaved);
611 DPL::OptionalString defaultLocale = dao.getDefaultlocale();
612 if (!!defaultLocale && !defaultNameSaved)
614 DPL::OptionalString name = dao.getLocalizedInfo(*defaultLocale).name;
615 generateWidgetName(manifest, uiApp, DPL::OptionalString::Null, name, defaultNameSaved);
619 if(!!m_context.widgetConfig.pkgname)
621 pkgname = *m_context.widgetConfig.pkgname;
622 uiApp.setAppid(pkgname);
626 if(!!m_context.widgetConfig.guid) {
627 uiApp.setExtraid(*m_context.widgetConfig.guid);
629 if(!pkgname.empty()) {
630 uiApp.setExtraid(DPL::String(L"http://") + pkgname);
635 uiApp.setType(DPL::FromASCIIString("webapp"));
636 manifest.setType(L"wgt");
637 uiApp.setTaskmanage(true);
640 void TaskManifestFile::generateWidgetName(Manifest & manifest, UiApplication &uiApp, const DPL::OptionalString& tag, DPL::OptionalString name, bool & defaultNameSaved)
646 LocalizationUtils::BCP47LanguageTagToLocale(*tag);
648 if (!locale.empty()) {
649 uiApp.addLabel(LabelType(*name,*tag));
653 uiApp.addLabel(LabelType(*name));
654 manifest.addLabel(LabelType(*name));
659 defaultNameSaved = true;
660 uiApp.addLabel(LabelType(*name));
661 manifest.addLabel(LabelType(*name));
666 void TaskManifestFile::setWidgetIcons(UiApplication & uiApp)
668 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
669 if (pkgname.IsNull()) {
670 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
673 //TODO this file will need to be updated when user locale preferences
675 Assert(!!m_context.widgetHandle);
676 WidgetDAOReadOnly dao(*m_context.widgetHandle);
678 WidgetDAOReadOnly::WidgetLocalizedIconList locList = dao.getLocalizedIconList();
679 WidgetDAOReadOnly::WidgetIconList list = dao.getIconList();
680 bool defaultIconSaved = false;
684 DPL::String i = it->widgetLocale;
685 DPL::OptionalString tag = getLangTag(i); // translate en -> en_US etc
686 if (tag.IsNull()) { tag = i; }
688 generateWidgetIcon(uiApp, tag, i, it->iconId, list, defaultIconSaved);
690 DPL::OptionalString defaultLocale = dao.getDefaultlocale();
691 if (!!defaultLocale && !defaultIconSaved)
696 if (it->widgetLocale == *defaultLocale)
703 generateWidgetIcon(uiApp, DPL::OptionalString::Null,
712 void TaskManifestFile::generateWidgetIcon(UiApplication & uiApp, const DPL::OptionalString& tag,
713 const DPL::String& language, int iconId, const WrtDB::WidgetDAOReadOnly::WidgetIconList & list,
714 bool & defaultIconSaved)
719 locale = LocalizationUtils::BCP47LanguageTagToLocale(*tag);
723 defaultIconSaved = true;
726 DPL::OptionalString src;
729 if (icon->iconId == iconId) {
734 DPL::String iconText;
735 iconText += getIconTargetFilename(language);
739 uiApp.addIcon(IconType(iconText,locale));
743 uiApp.addIcon(IconType(iconText));
748 void TaskManifestFile::setWidgetManifest(Manifest & manifest)
750 if(!!m_context.widgetConfig.pkgname)
752 manifest.setPackage(*m_context.widgetConfig.pkgname);
754 if(!!m_context.widgetConfig.version)
756 manifest.setVersion(*m_context.widgetConfig.version);
758 DPL::String email = (!!m_context.widgetConfig.configInfo.authorEmail ?
759 *m_context.widgetConfig.configInfo.authorEmail : L"");
760 DPL::String href = (!!m_context.widgetConfig.configInfo.authorHref ?
761 *m_context.widgetConfig.configInfo.authorHref : L"");
762 DPL::String name = (!!m_context.widgetConfig.configInfo.authorName ?
763 *m_context.widgetConfig.configInfo.authorName : L"");
764 manifest.addAuthor(Author(email,href,L"",name));
767 void TaskManifestFile::setWidgetOtherInfo(UiApplication & uiApp)
769 uiApp.setNodisplay(false);
771 //There is no "X-TIZEN-PackageType=wgt"
772 //There is no X-TIZEN-PackageID in manifest "X-TIZEN-PackageID=" << DPL::ToUTF8String(*widgetID).c_str()
773 //There is no Comment in pkgmgr "Comment=Widget application"
774 //that were in desktop file
777 void TaskManifestFile::setAppServiceInfo(UiApplication & uiApp)
779 Assert(!!m_context.widgetHandle);
780 WidgetDAOReadOnly dao(*m_context.widgetHandle);
781 WidgetApplicationServiceList appServiceList;
782 dao.getAppServiceList(appServiceList);
784 if (appServiceList.empty()) {
785 LogInfo("Widget doesn't contain application service");
789 // x-tizen-svc=http://tizen.org/appsvc/operation/pick|NULL|image;
790 FOREACH(it, appServiceList) {
791 ApplicationService appService;
792 if (!it->operation.empty()) {
793 appService.addOperation(it->operation);
795 if (!it->scheme.empty()) {
796 appService.addUri(it->scheme);
798 if (!it->mime.empty()) {
799 appService.addMime(it->mime);
801 uiApp.addApplicationService(appService);
805 } //namespace WidgetInstall