#include "wgt/step/filesystem/step_create_symbolic_link.h"
#include "wgt/step/filesystem/step_wgt_patch_icons.h"
#include "wgt/step/filesystem/step_wgt_patch_storage_directories.h"
+#include "wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h"
#include "wgt/step/pkgmgr/step_generate_xml.h"
#include "wgt/step/security/step_check_settings_level.h"
#include "wgt/step/security/step_check_wgt_background_category.h"
AddStep<ci::configuration::StepParseManifest>(
ci::configuration::StepParseManifest::ManifestLocation::PACKAGE,
ci::configuration::StepParseManifest::StoreLocation::NORMAL);
+ AddStep<wgt::filesystem::StepWgtUndoPatchStorageDirectories>();
AddStep<hybrid::configuration::StepStashTpkConfig>();
AddStep<ci::configuration::StepParseManifest>(
ci::configuration::StepParseManifest::ManifestLocation::INSTALLED,
ValidateExternalPackage(pkgid, {appid});
}
+TEST_F(SmokeTest, SharedRes24) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes24.wgt";
+ std::string pkgid = "smokeSh2xx";
+ std::string appid = "smokeSh2xx.SharedRes24";
+ ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid});
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "NOT-SHARED-WGT")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "NOT-SHARED-WGT")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30.wgt";
+ std::string pkgid = "smokeSh3xx";
+ std::string appid = "smokeSh3xx.SharedRes30";
+ ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid});
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30Delta) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30Delta.wgt";
+ bf::path delta_package = kSmokePackagesDirectory / "SharedRes30Delta.delta";
+ std::string pkgid = "smokeSh3De";
+ std::string appid = "smokeSh3De.SharedRes30Delta";
+ ASSERT_EQ(DeltaInstall(path, delta_package, PackageType::WGT),
+ ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid});
+ // Check delta modifications
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30Hybrid) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30Hybrid.wgt";
+ std::string pkgid = "smokeSh3Hy";
+ std::string appid1 = "smokeSh3Hy.SharedRes30Hybrid";
+ std::string appid2 = "smokeSh3Hy.sharedres30hybridserivce";
+ ASSERT_EQ(Install(path, PackageType::HYBRID), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid1, appid2});
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT")); // NOLINT
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30HybridDelta) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30HybridDelta.wgt";
+ bf::path delta_package = kSmokePackagesDirectory / "SharedRes30HybridDelta.delta";
+ std::string pkgid = "smokeSh3HD";
+ std::string appid1 = "smokeSh3HD.SharedRes30HybridDelta";
+ std::string appid2 = "smokeSh3HD.sharedres30hybriddeltaserivce";
+ ASSERT_EQ(DeltaInstall(path, delta_package, PackageType::HYBRID),
+ ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid1, appid2});
+ // Check delta modifications
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK-2")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK-2")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+}
+
} // namespace common_installer
int main(int argc, char** argv) {
if (!CreatePrivateTmpDir())
return Status::APP_DIR_ERROR;
- char version = context_->manifest_data.get()->api_version[0];
- if ((version-'0') >= 3) {
- LOG(DEBUG) << "Copying widget's shared/ directory";
+ int version = std::stoi(context_->manifest_data.get()->api_version);
+ if (version >= 3) {
+ LOG(DEBUG) << "Symlinking widget's shared/res directory content in "
+ << context_->pkg_path.get();
if (!ShareDirFor3x())
return Status::APP_DIR_ERROR;
}
}
bool StepWgtPatchStorageDirectories::ShareDirFor3x() {
+ // check if ${pkg_path}/res/wgt/shared/res exists
+ bf::path wgt_shared_res_dir =
+ context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
+ if (!bf::exists(wgt_shared_res_dir))
+ return true;
+ // create ${pkg_path}/shared/res
bf::path shared_dir = context_->pkg_path.get() / kSharedLocation;
if (!bf::exists(shared_dir)) {
bs::error_code error;
return false;
}
}
- bf::path src = context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
- if (!bf::exists(src))
- return true;
- if (!bf::is_directory(src)) {
- LOG(WARNING) << "Widget's shared/res/ is not directory";
- return true;
+ bf::path shared_res_dir = context_->pkg_path.get() / kSharedResLocation;
+ if (!bf::exists(shared_res_dir)) {
+ bs::error_code error;
+ bf::create_directory(shared_res_dir, error);
+ if (error) {
+ LOG(ERROR) << "Failed to create directory: " << shared_res_dir;
+ return false;
+ }
}
- bf::path dst = context_->pkg_path.get() / kSharedResLocation;
- if (!common_installer::MoveDir(src, dst,
- common_installer::FS_MERGE_SKIP)) {
- LOG(ERROR) << "Failed to move shared data from res/wgt to shared";
- return false;
+ // link all ${pkg_path}/res/wgt/shared/res content to ${pkg_path}/shared/res
+ bf::directory_iterator end_itr;
+ for (bf::directory_iterator itr(wgt_shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_target = itr->path();
+ if (bf::is_symlink(link_target)) {
+ continue;
+ }
+ bf::path link_file = shared_res_dir / link_target.filename();
+ if (bf::exists(link_file)) {
+ LOG(DEBUG) << "shared/res linking: skipping existing " << link_file;
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: creating link " << link_file;
+ bs::error_code error;
+ bf::create_symlink(link_target, link_file, error);
+ if (error) {
+ LOG(ERROR) << "shared/res linking: linking failed for " << link_file
+ << ": " << boost::system::system_error(error).what();
+ return false;
+ }
}
-
- bs::error_code error_code;
- bf::create_symlink(dst, src, error_code);
- if (error_code) {
- LOG(ERROR) << "Failed to create symbolic link for shared dir"
- << boost::system::system_error(error_code).what();
- return false;
+ // link all ${pkg_path}/shared/res content to ${pkg_path}/res/wgt/shared/res
+ for (bf::directory_iterator itr(shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_target = itr->path();
+ if (bf::is_symlink(link_target)) {
+ continue;
+ }
+ bf::path link_file = wgt_shared_res_dir / link_target.filename();
+ if (bf::exists(link_file)) {
+ LOG(DEBUG) << "shared/res linking: skipping existing " << link_file;
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: creating link " << link_file;
+ bs::error_code error;
+ bf::create_symlink(link_target, link_file, error);
+ if (error) {
+ LOG(ERROR) << "shared/res linking: linking failed for " << link_file
+ << ": " << boost::system::system_error(error).what();
+ return false;
+ }
}
return true;
}
bool StepWgtPatchStorageDirectories::CreatePrivateTmpDir() {
- bs::error_code error_code;
bf::path tmp_path = context_->pkg_path.get() / kTemporaryData;
- bf::create_directory(tmp_path, error_code);
- if (error_code) {
+ if (bf::exists(tmp_path) && bf::is_directory(tmp_path)) {
+ return true;
+ }
+ bs::error_code error;
+ bf::create_directory(tmp_path, error);
+ if (error) {
LOG(ERROR) << "Failed to create private temporary directory for package";
return false;
}
/**
* \brief Installation (WGT).
- * Responsible for copying widgets shared/ directory into package's
- * shared/ directory for tizen widget with api version >= 3.0
+ * Responsible for linking the content of widget's shared/res directory
+ * into package's shared/res directory and vice versa for Tizen widget
+ * with API version >= 3.0
*/
class StepWgtPatchStorageDirectories :
public common_installer::Step {
--- /dev/null
+// 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 "wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <common/utils/file_util.h>
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+
+namespace {
+
+const char kSharedLocation[] = "shared";
+const char kSharedResLocation[] = "shared/res";
+const char kResWgtSubPath[] = "res/wgt";
+
+} // namespace
+
+namespace wgt {
+namespace filesystem {
+
+common_installer::Step::Status StepWgtUndoPatchStorageDirectories::process() {
+ int version = std::stoi(context_->manifest_data.get()->api_version);
+ if (version >= 3) {
+ LOG(DEBUG) << "Unlinking widget's shared/res directory content in "
+ << context_->pkg_path.get();
+ if (!UndoShareDirFor3x())
+ return Status::APP_DIR_ERROR;
+ }
+
+ return Status::OK;
+}
+
+bool StepWgtUndoPatchStorageDirectories::UndoShareDirFor3x() {
+ // check if ${pkg_path}/shared/res exists
+ bf::path shared_res_dir = context_->pkg_path.get() / kSharedResLocation;
+ bf::path wgt_shared_res_dir =
+ context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
+ if (!bf::exists(shared_res_dir))
+ return true;
+ // delete symlinks in ${pkg_path}/shared/res
+ if (bf::exists(shared_res_dir)) {
+ bf::directory_iterator end_itr;
+ for (bf::directory_iterator itr(shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_file = itr->path();
+ if (!bf::is_symlink(link_file)) {
+ continue;
+ }
+ bf::path link_target = bf::read_symlink(link_file);
+ if (link_target.native().substr(0, wgt_shared_res_dir.native().length()) !=
+ wgt_shared_res_dir.native()) {
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: removing symlink " << link_file;
+ bs::error_code error;
+ bf::remove(link_file, error);
+ if (error) {
+ LOG(ERROR) << "Failed to remove symlink " << link_file;
+ return false;
+ }
+ }
+ }
+ // delete symlinks in ${pkg_path}/res/wgt/shared/res
+ if (bf::exists(wgt_shared_res_dir)) {
+ bf::directory_iterator end_itr;
+ for (bf::directory_iterator itr(wgt_shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_file = itr->path();
+ if (!bf::is_symlink(link_file)) {
+ continue;
+ }
+ bf::path link_target = bf::read_symlink(link_file);
+ if (link_target.native().substr(0, shared_res_dir.native().length()) !=
+ shared_res_dir.native()) {
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: removing symlink " << link_file;
+ bs::error_code error;
+ bf::remove(link_file, error);
+ if (error) {
+ LOG(ERROR) << "Failed to remove symlink " << link_file;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace filesystem
+} // namespace wgt
--- /dev/null
+// 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 WGT_STEP_FILESYSTEM_STEP_WGT_UNDO_PATCH_STORAGE_DIRECTORIES_H_
+#define WGT_STEP_FILESYSTEM_STEP_WGT_UNDO_PATCH_STORAGE_DIRECTORIES_H_
+
+#include <common/step/step.h>
+#include <manifest_parser/utils/logging.h>
+
+namespace wgt {
+namespace filesystem {
+
+/**
+ * \brief Installation (WGT).
+ * Responsible for unlinking the content of widget's shared/res directory
+ * into package's shared/res directory and vice versa for Tizen widget
+ * with API version >= 3.0
+ */
+class StepWgtUndoPatchStorageDirectories :
+ 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 { return Status::OK; }
+
+ private:
+ bool UndoShareDirFor3x();
+
+ STEP_NAME(UndoPatchWgtStorageDirectories)
+};
+
+} // namespace filesystem
+} // namespace wgt
+
+#endif // WGT_STEP_FILESYSTEM_STEP_WGT_UNDO_PATCH_STORAGE_DIRECTORIES_H_
#include "wgt/step/filesystem/step_wgt_patch_storage_directories.h"
#include "wgt/step/filesystem/step_wgt_prepare_package_directory.h"
#include "wgt/step/filesystem/step_wgt_resource_directory.h"
+#include "wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h"
#include "wgt/step/filesystem/step_wgt_update_package_directory.h"
#include "wgt/step/pkgmgr/step_generate_xml.h"
#include "wgt/step/security/step_add_default_privileges.h"
AddStep<ci::configuration::StepParsePreload>();
AddStep<ci::configuration::StepCheckTizenVersion>();
AddStep<ci::filesystem::StepEnableExternalMount>();
+ AddStep<wgt::filesystem::StepWgtUndoPatchStorageDirectories>();
AddStep<ci::filesystem::StepDeltaPatch>("res/wgt/");
AddStep<ci::filesystem::StepDisableExternalMount>();
AddStep<wgt::configuration::StepCheckStartFiles>();