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 << GlobalConfig::GetUserInstalledWidgetPath() << "/";
135 real_path << pkgname << "/";
136 real_path << GlobalConfig::GetUserWidgetExecPath() << "/" <<
137 m_context.widgetHandle;
138 std::string clientExeStr = GlobalConfig::GetWrtClientExec();
140 LogInfo("link -s " << clientExeStr << " " << real_path.str());
141 symlink(clientExeStr.c_str(), real_path.str().c_str());
143 m_context.job->UpdateProgress(
144 InstallerContext::INSTALL_CREATE_EXECFILE,
145 "Widget execfile creation Finished");
148 void TaskManifestFile::stepCopyIconFiles()
150 LogDebug("CopyIconFiles");
152 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
153 if (pkgname.IsNull()) {
154 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
156 Assert(!!m_context.widgetHandle);
158 WidgetDAOReadOnly dao(*m_context.widgetHandle);
159 WidgetDAOReadOnly::WidgetLocalizedIconList locList = dao.getLocalizedIconList();
160 WidgetDAOReadOnly::WidgetIconList list = dao.getIconList();
164 DPL::String i = it->widgetLocale;
165 DPL::OptionalString src;
168 if (icon->iconId == it->iconId) {
172 LogDebug("Icon for locale: " << i << "is : " << src);
174 std::ostringstream sourceFile;
175 std::ostringstream targetFile;
178 if (m_context.browserRequest) {
179 size_t pos = m_context.widgetSource.rfind("/");
180 sourceFile << m_context.widgetSource.substr(0, pos+1);
182 sourceFile << GlobalConfig::GetUserInstalledWidgetPath() << "/";
183 sourceFile << pkgname << "/";
184 sourceFile << GlobalConfig::GetWidgetSrcPath() << "/";
188 sourceFile << "locales/" << i << "/";
193 targetFile << GlobalConfig::GetUserWidgetDesktopIconPath() << "/";
194 targetFile << getIconTargetFilename(i);
196 if (m_context.browserRequest) {
197 m_context.installedIconPath = targetFile.str();
200 //Use WRT default (not from the widget) only if widget default (not
201 // localized) doesn't exist.
203 LogError("Using Default Icon for widget");
204 sourceFile << GlobalConfig::GetUserWidgetDefaultIconFile();
210 LogDebug("Copying icon: " << sourceFile.str() <<
211 " -> " << targetFile.str());
213 icon_list.push_back(targetFile.str());
217 DPL::FileInput input(sourceFile.str());
218 DPL::FileOutput output(targetFile.str());
219 DPL::Copy(&input, &output);
222 Catch(DPL::FileInput::Exception::Base)
224 // Error while opening or closing source file
225 //ReThrowMsg(InstallerException::CopyIconFailed, sourceFile.str());
227 "Copying widget's icon failed. Widget's icon will not be"\
228 "available from Main Screen");
231 Catch(DPL::FileOutput::Exception::Base)
233 // Error while opening or closing target file
234 //ReThrowMsg(InstallerException::CopyIconFailed, targetFile.str());
236 "Copying widget's icon failed. Widget's icon will not be"\
237 "available from Main Screen");
240 Catch(DPL::CopyFailed)
242 // Error while copying
243 //ReThrowMsg(InstallerException::CopyIconFailed, targetFile.str());
245 "Copying widget's icon failed. Widget's icon will not be"\
246 "available from Main Screen");
250 m_context.job->UpdateProgress(
251 InstallerContext::INSTALL_COPY_ICONFILE,
252 "Widget iconfile copy Finished");
255 void TaskManifestFile::stepBackupIconFiles()
257 LogDebug("Backup Icon Files");
259 backup_dir << GlobalConfig::GetUserInstalledWidgetPath();
260 backup_dir << "/" << m_context.widgetConfig.pkgname;
261 backup_dir << "/" << "backup" << "/";
265 m_context.job->UpdateProgress(
266 InstallerContext::INSTALL_BACKUP_ICONFILE,
267 "New Widget icon file backup Finished");
270 void TaskManifestFile::stepAbortIconFiles()
272 LogDebug("Abrot Icon Files");
273 FOREACH(it, icon_list)
275 LogDebug("Remove Update Icon : " << (*it));
276 unlink((*it).c_str());
279 std::ostringstream b_icon_dir;
280 b_icon_dir << backup_dir.str() << "icons";
282 std::list<std::string> fileList;
283 getFileList(b_icon_dir.str().c_str(), fileList);
285 FOREACH(back_icon, fileList)
287 std::ostringstream res_file;
288 res_file << GlobalConfig::GetUserWidgetDesktopIconPath();
289 res_file << "/" << (*back_icon);
291 std::ostringstream backup_file;
292 backup_file << b_icon_dir.str() << "/" << (*back_icon);
296 DPL::FileInput input(backup_file.str());
297 DPL::FileOutput output(res_file.str());
298 DPL::Copy(&input, &output);
300 Catch(DPL::FileInput::Exception::Base)
302 LogError("Restoration icon File Failed." << backup_file.str()
303 << " to " << res_file.str());
306 Catch(DPL::FileOutput::Exception::Base)
308 LogError("Restoration icon File Failed." << backup_file.str()
309 << " to " << res_file.str());
311 Catch(DPL::CopyFailed)
313 LogError("Restoration icon File Failed." << backup_file.str()
314 << " to " << res_file.str());
319 void TaskManifestFile::stepUpdateFinalize()
321 LogDebug("Finished Update Desktopfile");
324 DPL::String TaskManifestFile::getIconTargetFilename(
325 const DPL::String& languageTag) const
327 DPL::OStringStream filename;
328 DPL::Optional<DPL::String> pkgname = m_context.widgetConfig.pkgname;
329 if (pkgname.IsNull()) {
330 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
333 filename << DPL::ToUTF8String(*pkgname).c_str();
335 if (!languageTag.empty()) {
336 DPL::OptionalString tag = getLangTag(languageTag); // translate en -> en_US etc
337 if (tag.IsNull()) { tag = languageTag; }
339 LocalizationUtils::BCP47LanguageTagToLocale(*tag);
342 filename << L"." << languageTag;
344 filename << L"." << locale;
349 return filename.str();
352 void TaskManifestFile::stepFinalize()
354 LogInfo("Finished ManifestFile step");
357 void TaskManifestFile::saveLocalizedKey(std::ofstream &file,
358 const DPL::String& key,
359 const DPL::String& languageTag)
362 LocalizationUtils::BCP47LanguageTagToLocale(languageTag);
365 if (!locale.empty()) {
366 file << "[" << locale << "]";
371 void TaskManifestFile::updateAilInfo()
373 // Update ail for desktop
374 std::string cfgPkgname =
375 DPL::ToUTF8String(*m_context.widgetConfig.pkgname);
376 const char* pkgname = cfgPkgname.c_str();
378 LogDebug("Update ail desktop : " << pkgname );
379 ail_appinfo_h ai = NULL;
382 ret = ail_package_get_appinfo(pkgname, &ai);
384 ail_package_destroy_appinfo(ai);
387 if (AIL_ERROR_NO_DATA == ret) {
388 if (ail_desktop_add(pkgname) < 0) {
389 LogDebug("Failed to add ail desktop : " << pkgname);
391 } else if (AIL_ERROR_OK == ret) {
392 if (ail_desktop_update(pkgname) < 0) {
393 LogDebug("Failed to update ail desktop : " << pkgname);
398 void TaskManifestFile::backupIconFiles()
400 LogInfo("Backup Icon Files");
402 std::ostringstream b_icon_dir;
403 b_icon_dir << backup_dir.str() << "icons";
405 LogDebug("Create icon backup folder : " << b_icon_dir.str());
406 _WrtMakeDir(b_icon_dir.str().c_str(), 0755, WRT_FILEUTILS_RECUR);
408 std::list<std::string> fileList;
409 getFileList(GlobalConfig::GetUserWidgetDesktopIconPath(), fileList);
410 std::string pkgname = DPL::ToUTF8String(*m_context.widgetConfig.pkgname);
412 FOREACH(it, fileList)
414 if (0 == (strncmp((*it).c_str(), pkgname.c_str(),
415 strlen(pkgname.c_str())))) {
416 std::ostringstream icon_file, backup_icon;
417 icon_file << GlobalConfig::GetUserWidgetDesktopIconPath();
418 icon_file << "/" << (*it);
420 backup_icon << b_icon_dir.str() << "/" << (*it);
422 LogDebug("Backup icon file " << icon_file.str() << " to " <<
426 DPL::FileInput input(icon_file.str());
427 DPL::FileOutput output(backup_icon.str());
428 DPL::Copy(&input, &output);
430 Catch(DPL::FileInput::Exception::Base)
432 LogError("Backup Desktop File Failed.");
433 ReThrowMsg(Exceptions::BackupFailed, icon_file.str());
436 Catch(DPL::FileOutput::Exception::Base)
438 LogError("Backup Desktop File Failed.");
439 ReThrowMsg(Exceptions::BackupFailed, backup_icon.str());
441 Catch(DPL::CopyFailed)
443 LogError("Backup Desktop File Failed.");
444 ReThrowMsg(Exceptions::BackupFailed, backup_icon.str());
446 unlink((*it).c_str());
451 void TaskManifestFile::getFileList(const char* path,
452 std::list<std::string> &list)
454 DIR* dir = opendir(path);
456 LogError("icon directory doesn't exist");
457 ThrowMsg(Exceptions::InternalError, path);
460 struct dirent* d_ent;
462 if ((d_ent = readdir(dir))) {
463 if(strcmp(d_ent->d_name, ".") == 0 ||
464 strcmp(d_ent->d_name, "..") == 0) {
467 std::string file_name = d_ent->d_name;
468 list.push_back(file_name);
473 void TaskManifestFile::stepGenerateManifest()
475 DPL::String pkgname = *m_context.widgetConfig.pkgname;
476 manifest_name = pkgname + L".xml";
477 manifest_file += L"/tmp/" + manifest_name;
479 //libxml - init and check
480 LibxmlSingleton::Instance().init();
482 writeManifest(manifest_file);
486 m_context.job->UpdateProgress(
487 InstallerContext::INSTALL_CREATE_MANIFEST,
488 "Widget Manifest Creation Finished");
491 void TaskManifestFile::stepParseManifest()
493 int code = pkgmgr_parser_parse_manifest_for_installation(
494 DPL::ToUTF8String(manifest_file).c_str(), NULL);
498 LogError("Manifest parser error: " << code);
499 ThrowMsg(ManifestParsingError, "Parser returncode: " << code);
502 // TODO : It will be removed. AIL update is temporary code request by pkgmgr team.
505 m_context.job->UpdateProgress(
506 InstallerContext::INSTALL_CREATE_MANIFEST,
507 "Widget Manifest Parsing Finished");
508 LogDebug("Manifest parsed");
511 void TaskManifestFile::stepParseUpgradedManifest()
513 int code = pkgmgr_parser_parse_manifest_for_upgrade(
514 DPL::ToUTF8String(manifest_file).c_str(), NULL);
518 LogError("Manifest parser error: " << code);
519 ThrowMsg(ManifestParsingError, "Parser returncode: " << code);
522 // TODO : It will be removed. AIL update is temporary code request by pkgmgr team.
525 m_context.job->UpdateProgress(
526 InstallerContext::INSTALL_CREATE_MANIFEST,
527 "Widget Manifest Parsing Finished");
528 LogDebug("Manifest parsed");
531 void TaskManifestFile::validateManifest()
533 int code = pkgmgr_parser_check_manifest_validation(
534 DPL::ToUTF8String(manifest_name).c_str());
538 LogError("Manifest validation error");
539 //TODO: manifest files are not yet validating properly because of href
540 // attribute in author element (incompatible types in W3C spec. and
542 //ThrowMsg(ManifestValidationError, "Validation returncode: " << code);
545 m_context.job->UpdateProgress(
546 InstallerContext::INSTALL_CREATE_MANIFEST,
547 "Widget Manifest Validation Finished");
548 LogDebug("Manifest validated");
551 void TaskManifestFile::commitManifest()
553 LogDebug("Commiting manifest file : " << manifest_file);
555 std::ostringstream destFile;
556 destFile << "/opt/share/packages" << "/"; //TODO constant with path
557 destFile << DPL::ToUTF8String(manifest_name);
558 LogInfo("cp " << manifest_file << " " << destFile.str());
560 DPL::FileInput input(DPL::ToUTF8String(manifest_file));
561 DPL::FileOutput output(destFile.str());
562 DPL::Copy(&input, &output);
563 LogDebug("Manifest writen to: " << destFile.str());
566 unlink((DPL::ToUTF8String(manifest_file)).c_str());
567 manifest_file = DPL::FromUTF8String(destFile.str().c_str());
570 void TaskManifestFile::writeManifest(const DPL::String & path)
572 LogDebug("Generating manifest file : " << path);
576 setWidgetExecPath(uiApp);
577 setWidgetName(manifest, uiApp);
578 setWidgetIcons(uiApp);
579 setWidgetManifest(manifest);
580 setWidgetOtherInfo(uiApp);
581 setAppServiceInfo(uiApp);
583 manifest.addUiApplication(uiApp);
584 manifest.generate(path);
585 LogDebug("Manifest file serialized");
588 void TaskManifestFile::setWidgetExecPath(UiApplication & uiApp)
590 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
591 if (pkgname.IsNull()) {
592 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
595 std::ostringstream path;
596 path << GlobalConfig::GetUserInstalledWidgetPath() << "/" << *pkgname << "/";
597 path << GlobalConfig::GetUserWidgetExecPath() << "/" << *m_context.widgetHandle;
598 uiApp.setExec(DPL::FromASCIIString(path.str()));
601 void TaskManifestFile::setWidgetName(Manifest & manifest, UiApplication & uiApp)
603 Assert(!!m_context.widgetHandle);
604 WidgetDAOReadOnly dao(*m_context.widgetHandle);
605 LanguageTagsList languageTags(dao.getLanguageTags());
606 bool defaultNameSaved = false;
609 FOREACH(i, languageTags)
611 DPL::OptionalString tag = getLangTag(*i); // translate en -> en_US etc
616 DPL::OptionalString name = dao.getLocalizedInfo(*i).name;
617 generateWidgetName(manifest, uiApp, tag, name, defaultNameSaved);
619 DPL::OptionalString defaultLocale = dao.getDefaultlocale();
620 if (!!defaultLocale && !defaultNameSaved)
622 DPL::OptionalString name = dao.getLocalizedInfo(*defaultLocale).name;
623 generateWidgetName(manifest, uiApp, DPL::OptionalString::Null, name, defaultNameSaved);
627 if(!!m_context.widgetConfig.pkgname)
629 pkgname = *m_context.widgetConfig.pkgname;
630 uiApp.setAppid(pkgname);
634 if(!!m_context.widgetConfig.guid) {
635 uiApp.setExtraid(*m_context.widgetConfig.guid);
637 if(!pkgname.empty()) {
638 uiApp.setExtraid(DPL::String(L"http://") + pkgname);
643 uiApp.setType(DPL::FromASCIIString("webapp"));
644 manifest.setType(L"wgt");
645 uiApp.setTaskmanage(true);
648 void TaskManifestFile::generateWidgetName(Manifest & manifest, UiApplication &uiApp, const DPL::OptionalString& tag, DPL::OptionalString name, bool & defaultNameSaved)
654 LocalizationUtils::BCP47LanguageTagToLocale(*tag);
656 if (!locale.empty()) {
657 uiApp.addLabel(LabelType(*name,*tag));
661 uiApp.addLabel(LabelType(*name));
662 manifest.addLabel(LabelType(*name));
667 defaultNameSaved = true;
668 uiApp.addLabel(LabelType(*name));
669 manifest.addLabel(LabelType(*name));
674 void TaskManifestFile::setWidgetIcons(UiApplication & uiApp)
676 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
677 if (pkgname.IsNull()) {
678 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
681 //TODO this file will need to be updated when user locale preferences
683 Assert(!!m_context.widgetHandle);
684 WidgetDAOReadOnly dao(*m_context.widgetHandle);
686 WidgetDAOReadOnly::WidgetLocalizedIconList locList = dao.getLocalizedIconList();
687 WidgetDAOReadOnly::WidgetIconList list = dao.getIconList();
688 bool defaultIconSaved = false;
692 DPL::String i = it->widgetLocale;
693 DPL::OptionalString tag = getLangTag(i); // translate en -> en_US etc
694 if (tag.IsNull()) { tag = i; }
696 generateWidgetIcon(uiApp, tag, i, it->iconId, list, defaultIconSaved);
698 DPL::OptionalString defaultLocale = dao.getDefaultlocale();
699 if (!!defaultLocale && !defaultIconSaved)
704 if (it->widgetLocale == *defaultLocale)
711 generateWidgetIcon(uiApp, DPL::OptionalString::Null,
720 void TaskManifestFile::generateWidgetIcon(UiApplication & uiApp, const DPL::OptionalString& tag, const DPL::String& language, int iconId, const WrtDB::WidgetDAOReadOnly::WidgetIconList & list, bool & defaultIconSaved)
725 locale = LocalizationUtils::BCP47LanguageTagToLocale(*tag);
729 defaultIconSaved = true;
732 DPL::OptionalString src;
735 if (icon->iconId == iconId) {
740 DPL::String iconText;
741 iconText += /*DPL::FromASCIIString(GlobalConfig::GetUserWidgetDesktopIconPath()) + L"/" +*/ getIconTargetFilename(language);
744 uiApp.addIcon(IconType(iconText,locale));
748 uiApp.addIcon(IconType(iconText));
753 void TaskManifestFile::setWidgetManifest(Manifest & manifest)
755 if(!!m_context.widgetConfig.pkgname)
757 manifest.setPackage(*m_context.widgetConfig.pkgname);
759 if(!!m_context.widgetConfig.version)
761 manifest.setVersion(*m_context.widgetConfig.version);
763 DPL::String email = (!!m_context.widgetConfig.configInfo.authorEmail ?
764 *m_context.widgetConfig.configInfo.authorEmail : L"");
765 DPL::String href = (!!m_context.widgetConfig.configInfo.authorHref ?
766 *m_context.widgetConfig.configInfo.authorHref : L"");
767 DPL::String name = (!!m_context.widgetConfig.configInfo.authorName ?
768 *m_context.widgetConfig.configInfo.authorName : L"");
769 manifest.addAuthor(Author(email,href,L"",name));
772 void TaskManifestFile::setWidgetOtherInfo(UiApplication & uiApp)
774 uiApp.setNodisplay(false);
776 //There is no "X-TIZEN-PackageType=wgt", there is not field in manifest
777 //There is no X-TIZEN-PackageID in manifest "X-TIZEN-PackageID=" << DPL::ToUTF8String(*widgetID).c_str()
778 //There is no Comment in pkgmgr "Comment=Widget application"
781 void TaskManifestFile::setAppServiceInfo(UiApplication & uiApp)
783 Assert(!!m_context.widgetHandle);
784 WidgetDAOReadOnly dao(*m_context.widgetHandle);
785 WidgetApplicationServiceList appServiceList;
786 dao.getAppServiceList(appServiceList);
788 if (appServiceList.empty()) {
789 LogInfo("Widget doesn't contain application service");
793 // x-tizen-svc=http://tizen.org/appsvc/operation/pick|NULL|image;
794 FOREACH(it, appServiceList) {
795 ApplicationService appService;
796 appService.addOperation(it->operation);
797 appService.addOperation(it->scheme);
798 appService.addOperation(it->mime);
799 uiApp.addApplicationService(appService);
803 } //namespace WidgetInstall