~aleteoryx/muditaos

09bab001d0d0479d6dc773b1ccc785277f4fd402 — Mateusz Piesta 3 years ago 44ef5dd
[MOS-807] Update scripts

Added update scripts for both variants:
UDM update and further 'normal' updates.

Minor updates to the directories layout
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
@@ 0,0 1,1 @@
test

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
@@ 0,0 1,1 @@
test

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