M .gitignore => .gitignore +4 -0
@@ 71,3 71,7 @@ image/assets/fonts/*
scripts/lua/test/assets*
scripts/lua/test/update/user/temp/*
scripts/lua/test/update/target/*
+scripts/lua/test/update/system/*
+scripts/lua/test/update_udm/user/temp/*
+scripts/lua/test/update_udm/target/*
+scripts/lua/test/update_udm/system/*
M CMakeLists.txt => CMakeLists.txt +1 -1
@@ 186,7 186,7 @@ add_directories(
TARGET system_directories_common
PREFIX ${SYSROOT_PATH}/system_a
DEPENDS assets
- DIRECTORIES log assets crash_dumps data bin db scripts
+ DIRECTORIES log assets crash_dumps data bin db scripts var
)
# Create and initialize product-specific databases
M cmake/modules/AddScripts.cmake => cmake/modules/AddScripts.cmake +1 -1
@@ 11,7 11,7 @@ function(add_scripts_target)
${_ARG_TARGET}
DEPENDS ${_ARG_DEPENDS}
- COMMAND ${PROJECT_SOURCE_DIR}/scripts/lua/install.sh ${_ARG_PRODUCT} ${_ARG_DEST_DIR}
+ COMMAND ${PROJECT_SOURCE_DIR}/scripts/lua/install.sh ${_ARG_PRODUCT} ${_ARG_DEST_DIR} udm
COMMENT
"Installing scripts for ${_ARG_PRODUCT} to ${_ARG_DEST_DIR} directory"
)
M module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.cpp => module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.cpp +1 -1
@@ 28,7 28,7 @@ namespace bsp::battery_charger
constexpr std::uint32_t i2cSubaddresSize = 1;
- const auto cfgFile = purefs::dir::getUserDataDirPath() / "batteryFuelGaugeConfig.cfg";
+ const auto cfgFile = purefs::dir::getSystemVarDirPath() / "batteryFuelGaugeConfig.cfg";
constexpr auto registersToStore = 0xFF + 1;
constexpr auto configFileSizeWithoutChecksum = registersToStore * sizeof(Register);
M module-services/service-fileindexer/StartupIndexer.cpp => module-services/service-fileindexer/StartupIndexer.cpp +1 -1
@@ 20,7 20,7 @@ namespace service::detail
using namespace std::literals;
using namespace std::chrono_literals;
- const auto lock_file_name = purefs::dir::getSystemDiskPath() / "data" / ".directory_is_indexed";
+ const auto lock_file_name = purefs::dir::getSystemVarDirPath() / ".directory_is_indexed";
constexpr auto indexing_interval = 50ms;
constexpr auto start_delay = 10000ms;
M module-vfs/paths/filesystem_paths.cpp => module-vfs/paths/filesystem_paths.cpp +4 -9
@@ 2,7 2,6 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <purefs/filesystem_paths.hpp>
-#include <hal/boot_control.h>
namespace
{
@@ 17,15 16,11 @@ namespace
constexpr inline auto PATH_TMP = "temp";
constexpr inline auto PATH_ASSETS = "assets";
constexpr inline auto PATH_DATA = "data";
+ constexpr inline auto PATH_VAR = "var";
} // namespace
namespace purefs
{
- std::filesystem::path createPath(const std::string &parent, const std::string &child) noexcept
- {
- return std::filesystem::path{parent} / child;
- }
-
namespace dir
{
std::filesystem::path getSystemDiskPath() noexcept
@@ 82,10 77,10 @@ namespace purefs
{
return getSystemDiskPath() / PATH_DATA;
}
-
- std::filesystem::path getUserDataDirPath() noexcept
+ std::filesystem::path getSystemVarDirPath() noexcept
{
- return getUserDiskPath() / PATH_DATA;
+ return getSystemDiskPath() / PATH_VAR;
}
+
} // namespace dir
} // namespace purefs
M module-vfs/paths/include/purefs/filesystem_paths.hpp => module-vfs/paths/include/purefs/filesystem_paths.hpp +1 -4
@@ 7,15 7,12 @@
namespace purefs
{
- std::filesystem::path createPath(const std::string &parent, const std::string &child) noexcept;
-
namespace dir
{
std::filesystem::path getSystemDiskPath() noexcept;
std::filesystem::path getUserDiskPath() noexcept;
std::filesystem::path getMfgConfPath() noexcept;
std::filesystem::path getDatabasesPath() noexcept;
- std::filesystem::path getSyncPackagePath() noexcept;
std::filesystem::path getLogsPath() noexcept;
std::filesystem::path getCrashDumpsPath() noexcept;
std::filesystem::path getUserMediaPath() noexcept;
@@ 23,7 20,7 @@ namespace purefs
std::filesystem::path getBootJSONPath() noexcept;
std::filesystem::path getAssetsDirPath() noexcept;
std::filesystem::path getSystemDataDirPath() noexcept;
- std::filesystem::path getUserDataDirPath() noexcept;
+ std::filesystem::path getSystemVarDirPath() noexcept;
} // namespace dir
namespace file
M scripts/lua/install.sh => scripts/lua/install.sh +7 -1
@@ 29,9 29,15 @@ if validate_product_selection; then
mkdir -p ${DESTINATION}
cp -r products/${PRODUCT}/assets ${DESTINATION}/assets/
- cp products/${PRODUCT}/product_updater.lua ${DESTINATION}/product_updater.lua
cp -r share ${DESTINATION}/share
cp -r migration/migration.lua ${DESTINATION}/share
cp *.lua ${DESTINATION}
+
+ if [ -n "$3" ]; then
+ echo "Generating UDM update package"
+ cp update_udm.lua ${DESTINATION}/update.lua
+ cp products/${PRODUCT}/update_product.lua ${DESTINATION}
+ fi
+ rm ${DESTINATION}/update_udm.lua
cd -
fi=
\ No newline at end of file
A scripts/lua/products/BellHybrid/update_product.lua => scripts/lua/products/BellHybrid/update_product.lua +17 -0
@@ 0,0 1,17 @@
+local paths = require('paths')
+local consts = require('consts')
+local helpers = require('helpers')
+local recovery = require('recovery')
+
+local update_product = {}
+
+function update_product.execute()
+ local old_music_dir = recovery.sys.user() .. "/music"
+ local new_music_dir = recovery.sys.user() .. "/media/app/relaxation"
+
+ assert(helpers.mkdirp(new_music_dir))
+ helpers.copy_dir(old_music_dir, new_music_dir)
+ helpers.rmdir(old_music_dir)
+end
+
+return update_product
D scripts/lua/products/PurePhone/product_updater.lua => scripts/lua/products/PurePhone/product_updater.lua +0 -30
@@ 1,30 0,0 @@
-local product_updater = {}
-
-local paths = require('paths')
-local helpers = require('helpers')
-local lfs = require('lfs')
-local paths = require('paths')
-
-function product_updater.is_migration_needed()
- local current_version = helpers.get_os_version(paths.version_file)
- local version = "1.5.0"
- assert(current_version >= version, string.format("Updating from version '%s' not supported", current_version))
- return current_version == version
-end
-
-function product_updater.execute()
- local old_music_dir = "/user/music"
- local new_music_dir = "/user/app/music_player"
- local old_battery_config = "/user/batteryFuelGaugeConfig.cfg"
- local new_battery_config = paths.data_dir .. "/batteryFuelGaugeConfig.cfg"
-
- assert(helpers.mkdirp(new_music_dir))
- helpers.copy_dir(old_music_dir, new_music_dir)
- helpers.rmdir(old_music_dir)
- helpers.copy_file(old_battery_config,new_battery_config)
- os.remove(old_battery_config)
-
-end
-
-return product_updater
-
A scripts/lua/products/PurePhone/update_product.lua => scripts/lua/products/PurePhone/update_product.lua +20 -0
@@ 0,0 1,20 @@
+local paths = require('paths')
+local consts = require('consts')
+local helpers = require('helpers')
+local recovery = require('recovery')
+
+local update_product = {}
+
+function update_product.execute()
+ local old_music_dir = recovery.sys.user() .. "/music"
+ local new_music_dir = recovery.sys.user() .. "/media/app/music_player"
+ local old_battery_config = recovery.sys.user() .. "/batteryFuelGaugeConfig.cfg"
+ local new_battery_config = paths.target.var_dir .. "/batteryFuelGaugeConfig.cfg"
+
+ assert(helpers.mkdirp(new_music_dir))
+ helpers.copy_dir(old_music_dir, new_music_dir)
+ helpers.rmdir(old_music_dir)
+ helpers.copy_file(old_battery_config, new_battery_config)
+end
+
+return update_product
M scripts/lua/share/consts.lua => scripts/lua/share/consts.lua +2 -1
@@ 1,5 1,6 @@
local consts = {}
consts.version_file = "version.json"
+consts.indexer_cache_file = ".directory_is_indexed"
-return consts>
\ No newline at end of file
+return consts
M scripts/lua/share/helpers.lua => scripts/lua/share/helpers.lua +20 -2
@@ 49,7 49,7 @@ local function build_path(prefix, name)
return prefix .. name
end
-local function strip_from_prefix(prefix,path)
+local function strip_from_prefix(prefix, path)
local name = path:gsub(prefix, "")
name = name:sub(2, -1)
return name
@@ 141,6 141,24 @@ function helpers.copy_dir(from, where)
end
end
+--- Copy directory recursively using regex filter
+-- @function copy_dir_filtered
+-- @param from source directory
+-- @param where target directory
+-- @param matcher regex expression
+function helpers.copy_dir_filtered(from, where, filter)
+ for filename, attr in dirtree(from) do
+ local name = strip_from_prefix(from, filename)
+ if name:match(filter) then
+ if attr.mode == "directory" then
+ assert(lfs.mkdir(build_path(where, name)))
+ else
+ helpers.copy_file(filename, build_path(where, name))
+ end
+ end
+ end
+end
+
--- Get the size of specified directory using regex filter
-- @function dir_size_filtered
-- @param path directory path
@@ 149,7 167,7 @@ end
function helpers.dir_size_filtered(path, filter)
local total_size = 0
for filename, attr in dirtree(path) do
- local name = strip_from_prefix(path,filename)
+ local name = strip_from_prefix(path, filename)
if name:match(filter) then
total_size = total_size + attr.size
end
M scripts/lua/share/paths.lua => scripts/lua/share/paths.lua +13 -1
@@ 5,7 5,9 @@ local paths = {}
local user_dir = recovery.sys.user()
local system_dir = recovery.sys.source_slot()
+local target_dir = recovery.sys.target_slot()
+paths.var_dir = system_dir .. "/var"
paths.data_dir = system_dir .. "/data"
paths.db_dir = system_dir .. "/db"
paths.db_factory_dir = paths.db_dir .. "/factory"
@@ 13,8 15,18 @@ paths.temp_dir = user_dir .. "/temp"
paths.update_dir = user_dir .. "/temp/update"
paths.migration_scripts_dir = paths.db_dir .. "/migration"
+local target = {}
+target.var_dir = target_dir .. "/var"
+target.data_dir = target_dir .. "/data"
+target.db_dir = target_dir .. "/db"
+target.db_factory_dir = target.db_dir .. "/factory"
+target.migration_scripts_dir = target.db_dir .. "/migration"
+target.file_indexer_cache = target.var_dir .. "/" .. consts.indexer_cache_file
+paths.target = target
+
paths.version_file = system_dir .. "/" .. consts.version_file
paths.backup_file = paths.temp_dir .. "/backup.tar"
-paths.file_indexer_cache = system_dir .. "/data/.directory_is_indexed"
+paths.update_file = paths.temp_dir .. "/update.tar"
+paths.file_indexer_cache = paths.var_dir .. "/" .. consts.indexer_cache_file
return paths
A scripts/lua/test/device/user/temp/backup.tar => scripts/lua/test/device/user/temp/backup.tar +0 -0
M scripts/lua/test/test.lua => scripts/lua/test/test.lua +78 -32
@@ 1,6 1,7 @@
package.path = package.path .. ";../?.lua;../?/?.lua;../share/?.lua;../share/?/?.lua"
local helpers = require('helpers')
+local lfs = require('lfs')
local recovery = {}
@@ 38,22 39,18 @@ bootctrl.slot = {
}
function bootctrl.mark_as_active(slot)
-
end
-function bootctrl.get_next_active()
-
+function bootctrl.mark_as_bootable(slot)
end
-function sys.source_slot()
- return "device/system"
+function bootctrl.get_next_active()
end
function sys.sleep(time)
end
function sys.set_os_boot_status()
-
end
function gui.clear()
@@ 63,6 60,7 @@ function gui.display_raw_img(width, height, data)
end
sys.user = stub()
+sys.source_slot = stub()
sys.target_slot = stub()
sys.boot_reason = stub()
sys.boot_reason_str = stub()
@@ 84,9 82,14 @@ local ppack = package.path
describe("Factory/backup/restore scripts", function()
package.path = ppack .. ";../products/PurePhone/?.lua"
+ recovery.sys.source_slot.returns("device/system")
recovery.sys.target_slot.returns("device/target")
recovery.sys.user.returns("device/user")
+ local function invoke_entry()
+ require('entry')
+ end
+
-- Force reload of the 'entry' module after execution of each unit test case
after_each(function()
package.loaded['entry'] = false
@@ 96,31 99,31 @@ describe("Factory/backup/restore scripts", function()
recovery.sys.free_space.returns(1024 * 1024 * 1024)
recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.factory)
recovery.sys.boot_reason_str.returns("factory")
- local entry = require('entry')
+ assert.has_no.error(invoke_entry)
end)
it("invoke backup script", function()
recovery.sys.free_space.returns(1024 * 1024 * 1024)
recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.backup)
recovery.sys.boot_reason_str.returns("backup")
- local entry = require('entry')
+ assert.has_no.error(invoke_entry)
end)
it("invoke backup script, no free space", function()
recovery.sys.free_space.returns(10)
recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.backup)
recovery.sys.boot_reason_str.returns("backup")
- local entry = require('entry')
+ assert.has_no.error(invoke_entry)
end)
it("invoke restore script", function()
recovery.sys.free_space.returns(1024 * 1024 * 1024)
recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.restore)
recovery.sys.boot_reason_str.returns("restore")
- local entry = require('entry')
+ assert.has_no.error(invoke_entry)
end)
it("invoke restore script, no free space", function()
recovery.sys.free_space.returns(10)
recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.restore)
recovery.sys.boot_reason_str.returns("restore")
- local entry = require('entry')
+ assert.has_no.error(invoke_entry)
end)
end)
@@ 134,44 137,87 @@ local function extract_test_package(path, where)
os.execute(string.format("tar xf %s -C %s", path, where))
end
-describe("Update scripts for PurePhone", function()
+describe("Update script", function()
recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.update)
recovery.sys.boot_reason_str.returns("update")
+ recovery.sys.source_slot.returns("update/system")
recovery.sys.target_slot.returns("update/target")
recovery.sys.user.returns("update/user")
package.loaded['paths'] = false
package.loaded['update'] = false
- it("Normal update", function()
- -- Prepare test directory and its data
- remove_test_package("update/target")
- remove_test_package("update/user/temp/update")
- extract_test_package("update/target.tar", "update")
- extract_test_package("update/update.tar", "update/user/temp")
-
- local entry = require('entry')
+ -- Prepare test directory and its data
+ remove_test_package("update/system")
+ remove_test_package("update/target")
+ remove_test_package("update/user/temp/update")
+ extract_test_package("update/system.tar", "update")
+ extract_test_package("update/target.tar", "update")
+ extract_test_package("update/update.tar", "update/user/temp")
+
+ it("invoke update script", function()
+ local update = require('update')
+ assert.has_no.error(update.execute)
end)
end)
-describe("Update scripts for BellHybrid", function()
- package.path = ppack .. ";../products/BellHybrid/?.lua"
+describe("Update script UDM - PurePhone", function()
+ package.path = ppack .. ";../products/PurePhone/?.lua"
recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.update)
recovery.sys.boot_reason_str.returns("update")
- recovery.sys.target_slot.returns("update/target")
- recovery.sys.user.returns("update/user")
+ recovery.sys.source_slot.returns("update_udm/system")
+ recovery.sys.target_slot.returns("update_udm/target")
+ recovery.sys.user.returns("update_udm/user")
package.loaded['paths'] = false
- package.loaded['update'] = false
+ package.loaded['update_udm'] = false
+ package.loaded['update_product'] = false
+
+ -- Prepare test directory and its data
+ remove_test_package("update_udm/system")
+ remove_test_package("update_udm/target")
+ remove_test_package("update_udm/user")
+ remove_test_package("update_udm/user/temp/update")
+
+ extract_test_package("update_udm/system.tar", "update_udm")
+ extract_test_package("update_udm/target.tar", "update_udm")
+ extract_test_package("update_udm/user.tar", "update_udm")
+ helpers.mkdirp("update_udm/user/temp")
+ extract_test_package("update_udm/update.tar", "update_udm/user/temp")
+
+ it("invoke update UDM script", function()
+ local update = require('update_udm')
+ assert.has_no.error(update.execute)
+ end)
+end)
- it("Normal update", function()
- -- Prepare test directory and its data
- remove_test_package("update/target")
- remove_test_package("update/user/temp/update")
- extract_test_package("update/target.tar", "update")
- extract_test_package("update/update.tar", "update/user/temp")
+describe("Update script UDM - BellHybrid", function()
+ package.path = ppack .. ";../products/BellHybrid/?.lua"
+ recovery.sys.boot_reason.returns(recovery.sys.boot_reason_codes.update)
+ recovery.sys.boot_reason_str.returns("update")
+ recovery.sys.source_slot.returns("update_udm/system")
+ recovery.sys.target_slot.returns("update_udm/target")
+ recovery.sys.user.returns("update_udm/user")
- local entry = require('entry')
+ package.loaded['paths'] = false
+ package.loaded['update_udm'] = false
+ package.loaded['update_product'] = false
+
+ -- Prepare test directory and its data
+ remove_test_package("update_udm/system")
+ remove_test_package("update_udm/target")
+ remove_test_package("update_udm/user")
+ remove_test_package("update_udm/user/temp/update")
+
+ extract_test_package("update_udm/system.tar", "update_udm")
+ extract_test_package("update_udm/target.tar", "update_udm")
+ extract_test_package("update_udm/user.tar", "update_udm")
+ helpers.mkdirp("update_udm/user/temp")
+ extract_test_package("update_udm/update.tar", "update_udm/user/temp")
+
+ it("invoke update UDM script", function()
+ local update = require('update_udm')
+ assert.has_no.error(update.execute)
end)
end)
A scripts/lua/test/update/system.tar => scripts/lua/test/update/system.tar +0 -0
A scripts/lua/test/update_udm/system.tar => scripts/lua/test/update_udm/system.tar +0 -0
A scripts/lua/test/update_udm/target.tar => scripts/lua/test/update_udm/target.tar +0 -0
A scripts/lua/test/update_udm/update.tar => scripts/lua/test/update_udm/update.tar +0 -0
A scripts/lua/test/update_udm/user.tar => scripts/lua/test/update_udm/user.tar +0 -0
A scripts/lua/test/update_udm/user/media/app/relaxation/test1.mp3 => scripts/lua/test/update_udm/user/media/app/relaxation/test1.mp3 +1 -0
A scripts/lua/test/update_udm/user/media/app/relaxation/test2.mp3 => scripts/lua/test/update_udm/user/media/app/relaxation/test2.mp3 +1 -0
M scripts/lua/update.lua => scripts/lua/update.lua +89 -1
@@ 1,11 1,99 @@
local update = {}
+local json = require('lunajson')
+local paths = require('paths')
+local consts = require('consts')
+local helpers = require('helpers')
+local recovery = require('recovery')
+local migration = require('migration')
update.script_name = "update.lua"
update.img_in_progress = "assets/gui_image_update_in_progress.bin"
update.img_success = "assets/gui_image_update_success.bin"
update.img_failure = "assets/gui_image_update_failed.bin"
+-- Match only files with '.db' extensions and omit such files inside subdirectories
+local match_db_files = '^[^%/]*%.db$'
+
+local function build_db_set(file)
+ local contents = helpers.read_whole_file(file)
+ local root = json.decode(contents)
+ local set = {}
+ for _, entry in pairs(root.databases) do
+ set[entry.name] = tonumber(entry.version)
+ end
+ return set
+end
+
+local function purge_target_slot()
+ local target_dir = recovery.sys.target_slot()
+ print(string.format("Removing target slot content, '%s'", target_dir))
+ helpers.rmdir_content(target_dir)
+end
+
+local function copy_update_package()
+ local target_dir = recovery.sys.target_slot()
+ print(string.format("Copying content of the update package '%s to '%s'", paths.update_dir, target_dir))
+ helpers.copy_dir(paths.update_dir, target_dir)
+end
+
+local function copy_databases()
+ local from = paths.db_dir
+ local to = recovery.sys.target_slot() .. "/db"
+ print(string.format("Copying databases from '%s' to '%s'", from, to))
+ helpers.copy_dir_filtered(from, to, match_db_files)
+end
+
+local function create_directories()
+ print("Creating 'log' and 'crash_dumps' directories")
+
+ local target_dir = recovery.sys.target_slot()
+ lfs.mkdir(target_dir .. "/log")
+ lfs.mkdir(target_dir .. "/crash_dumps")
+ lfs.mkdir(target_dir .. "/var")
+end
+
+local function migrate_db()
+ local version_file = paths.update_dir .. "/" .. consts.version_file
+
+ print("Performing database migration")
+ local dbset = build_db_set(version_file)
+ local result = migration.migrate(paths.target.db_dir, paths.target.migration_scripts_dir, dbset)
+ assert(result == migration.retcode.OK, string.format("Database migration process failed with %d", result))
+end
+
+local function remove_cache()
+ if helpers.exists(paths.target.file_indexer_cache) then
+ print(string.format("Removing cache file '%s'", paths.target.file_indexer_cache))
+ assert(os.remove(paths.target.file_indexer_cache))
+ end
+end
+
+local function copy_var_directory()
+ local from = paths.var_dir
+ local to = paths.target.var_dir
+ print(string.format("Copying '%s' to '%s'", from, to))
+ helpers.copy_dir(from, to)
+
+end
+
+local function exit()
+ print("Finishing update process")
+ helpers.rmdir(paths.update_dir)
+ os.remove(paths.update_file)
+ recovery.bootctrl.mark_as_bootable(recovery.bootctrl.get_next_active())
+ recovery.bootctrl.mark_as_active(recovery.bootctrl.get_next_active())
+ recovery.sys.set_os_boot_status(false)
+end
+
function update.execute()
+ purge_target_slot()
+ copy_update_package()
+ copy_databases()
+ create_directories()
+ migrate_db()
+ copy_var_directory()
+ remove_cache()
+ exit()
end
-return update>
\ No newline at end of file
+return update
A scripts/lua/update_udm.lua => scripts/lua/update_udm.lua +140 -0
@@ 0,0 1,140 @@
+local update = {}
+local lfs = require('lfs')
+local json = require('lunajson')
+local paths = require('paths')
+local consts = require('consts')
+local helpers = require('helpers')
+local recovery = require('recovery')
+local migration = require('migration')
+local update_product = require('update_product')
+
+update.script_name = "update.lua"
+update.img_in_progress = "assets/gui_image_update_in_progress.bin"
+update.img_success = "assets/gui_image_update_success.bin"
+update.img_failure = "assets/gui_image_update_failed.bin"
+
+-- Match only files with '.db' extensions and omit such files inside subdirectories
+local match_db_files = '^[^%/]*%.db$'
+
+local function build_db_set(file)
+ local contents = helpers.read_whole_file(file)
+ local root = json.decode(contents)
+ local set = {}
+ for _, entry in pairs(root.databases) do
+ set[entry.name] = tonumber(entry.version)
+ end
+ return set
+end
+
+local function purge_target_slot()
+ local target_dir = recovery.sys.target_slot()
+ print(string.format("Removing target slot content, '%s'", target_dir))
+ helpers.rmdir_content(target_dir)
+end
+
+local function copy_update_package()
+ local target_dir = recovery.sys.target_slot()
+ print(string.format("Copying content of the update package '%s to '%s'", paths.update_dir, target_dir))
+ helpers.copy_dir(paths.update_dir, target_dir)
+end
+
+local function copy_databases()
+ local from = paths.db_dir
+ local to = paths.target.db_dir
+ print(string.format("Copying databases from '%s' to '%s'", from, to))
+ helpers.copy_dir_filtered(from, to, match_db_files)
+end
+
+local function create_directories()
+ print("Creating 'log', 'crash_dumps' and 'var' directories")
+
+ local target_dir = recovery.sys.target_slot()
+ lfs.mkdir(target_dir .. "/log")
+ lfs.mkdir(target_dir .. "/crash_dumps")
+ lfs.mkdir(target_dir .. "/var")
+end
+
+local function migrate_db()
+ local target_dir = recovery.sys.target_slot()
+ local version_file = paths.update_dir .. "/" .. consts.version_file
+ local db_path = target_dir .. "/db"
+ local migration_dir = db_path .. "/migration"
+
+ print("Performing database migration")
+ local dbset = build_db_set(version_file)
+ local result = migration.migrate(db_path, migration_dir, dbset)
+ assert(result == migration.retcode.OK, string.format("Database migration process failed with %d", result))
+end
+
+local function exit()
+ print("Finishing update process")
+ helpers.rmdir(paths.update_dir)
+ os.remove(paths.update_file)
+ recovery.bootctrl.mark_as_bootable(recovery.bootctrl.get_next_active())
+ recovery.bootctrl.mark_as_active(recovery.bootctrl.get_next_active())
+ recovery.sys.set_os_boot_status(false)
+end
+
+local function repartition_filesystem()
+ print("Repartinioning 'MUDITAOS' and 'BACKUP' partitions and changing theirs labels")
+ recovery.sys.repartition_fs()
+end
+
+local function user_remove_directories()
+ print("->Removing backup, crash_dums, data, db, logs, tmp directories")
+ if helpers.exists(recovery.sys.user() .. "/backup") then
+ helpers.rmdir(recovery.sys.user() .. "/backup")
+ end
+ if helpers.exists(recovery.sys.user() .. "/crash_dumps") then
+ helpers.rmdir(recovery.sys.user() .. "/crash_dumps")
+ end
+ if helpers.exists(recovery.sys.user() .. "/data") then
+ helpers.rmdir(recovery.sys.user() .. "/data")
+ end
+ if helpers.exists(recovery.sys.user() .. "/db") then
+ helpers.rmdir(recovery.sys.user() .. "/db")
+ end
+ if helpers.exists(recovery.sys.user() .. "/logs") then
+ helpers.rmdir(recovery.sys.user() .. "/logs")
+ end
+ if helpers.exists(recovery.sys.user() .. "/tmp") then
+ helpers.rmdir(recovery.sys.user() .. "/tmp")
+ end
+end
+
+local function user_remove_files()
+ print("->Removing files")
+ helpers.rm_files_from_dir(recovery.sys.user())
+end
+
+local function user_create_directories()
+ print("->Creating media, temp directories")
+ lfs.mkdir(recovery.sys.user() .. "/media")
+ lfs.mkdir(recovery.sys.user() .. "/temp")
+end
+
+local function user_product_specific()
+ print("->Executing product specific steps")
+ update_product.execute()
+end
+
+local function adjust_user_partition_layout()
+ print("Adjusting user partition layout...")
+ user_remove_directories()
+ user_create_directories()
+ user_product_specific()
+ user_remove_files()
+end
+
+function update.execute()
+ repartition_filesystem()
+ purge_target_slot()
+ copy_update_package()
+ copy_databases()
+ create_directories()
+ migrate_db()
+ adjust_user_partition_layout()
+ exit()
+end
+
+return update