Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
upgrade_oniro.py 6.06 KiB
# SPDX-FileCopyrightText: Huawei Inc.
#
# SPDX-License-Identifier: Apache-2.0
# 
# A tool to upgrade to a newer version of Oniro

# Steps to upgrade:
# 1. Get the input from the user:
#   1.1. Target version
#   1.2. Build directory, can be empty or not and this will define some additional checks to perform
#   1.3. Machine and target to build, in order to test the upgraded build we need to know these things
#   1.4. Optional: Conf directory path, this can be specified in order to use a specific config directory.
#                   In case we have a clean build directory and this is not specified the default config will be used.
#   1.5. Optional: Flavour. In case the conf directory is not specified and the build directory is empty it becomes mandatory
#   1.6. Some other stuff to control the output of the tool (TBD)
#
# 2. Check for tool updates. If the newest version of Oniro has a new version of this script it should be upgraded before
#       Oniro's upgrade, then it should be run instead of the old one.
#
# 3. Pre-upgrade checks:
#   3.1. Check if "Target version" is newer than the current
#   3.2. Check if all the layers in the sample of Oniro are checked out in the correct state.
#   3.4. If the build directory is non-empty check if bblayers.conf have some additional layers, if positive flag them for the config update.
#   3.5. Flag all the .bbappends for update
#   3.6 Check if the flavor is correct if the conf dir is specified
#
# 4. Pre-upgrade backup to ensure that if something goes wrong we can restore a good state of the build. 
#       Option to also backup the build (tmp dir excluded) if the build directory is not empty.
#
# 5. Update:
#   5.1. Sync the repos
#   5.2. Update the .bbappends files (needs user confirmation) if needed
#   5.2. Run the script to init the environment
#   5.3. If specified copy the conf directory
#   5.4. Update the configs
#   5.5. If present delete the tmp directory
#   5.6. Build the target
# 6. In case of error let the user know that they can restore the old version using this tool
# 7. In case of a successful upgrade print/dump some additional information about the upgrade (CVE diff, buildhistory, ...)
#
# TODO think about a way to let the user know BEFORE the upgrade what changed so (s)he can choose. (maybe you can use git diff --compact-summary)
# TODO check if the script is executed in the top level directory of the project
# TODO check that if build_directory exists then it must be a directory

import argparse
import pathlib

script_description = "[WIP] A tool to upgrade to a newer version of Oniro"

# Script options
target_version = ""
build_directory = pathlib.Path()
machine = ""
flavour = ""
image = ""
conf_directory = pathlib.Path()

def init_script_options():
    parser = argparse.ArgumentParser(description=script_description)

    # TODO a choice could be added in the version by checking all the tags of Oniro
    parser.add_argument("-tv", "--target-version", type=str, required=True,
                        help="Specify the target version of Oniro you want to upgrade to")
    parser.add_argument("-d", "--build-directory", type=pathlib.Path, required=True,
                        help="Path to the build directory you want to use (can be non-existent)")
    # TODO a choice could be added in the machine
    parser.add_argument("-m", "--machine", type=str, default="qemux86-64",
                        help="The target machine for the Oniro build. (qemux86-64 by default)")
    # TODO the option gathering can be automated by looking at oniro/flavours/
    parser.add_argument("-f", "--flavour", type=str, choices=["linux", "zephyr", "freertos"], default="linux",
                        help="The flavor for the Oniro build. (linux by default)")
    # TODO the option gathering can be automated by looking at oniro/meta-oniro-core/recipes-core/images
    parser.add_argument("-i", "--image", type=str, default="oniro-image-base",
                        choices=["oniro-image-base", "oniro-image-base-tests", "oniro-image-extra", "oniro-image-extra-tests"],
                        help = "The image that will be built to check if the upgrade is successful (oniro-image-base by default)")
    parser.add_argument("-c", "--conf-directory", type=pathlib.Path,
                        help="Path to the config directory you want to use. If omitted the default configs will be use.")
    

    parsed_args = vars(parser.parse_args())
    global target_version, build_directory, machine, flavour, image, conf_directory
    target_version = parsed_args["target_version"]
    build_directory = parsed_args["build_directory"]
    machine = parsed_args["machine"]
    flavour = parsed_args["flavour"]
    image = parsed_args["image"]
    conf_directory = parsed_args["conf_directory"]

def upgrade_tool():
    # TODO
    return

def perform_pre_upgrade_checks():
    # TODO
    return

def backup_oniro():
    # This will back up:
    #   - All layers specified in the Oniro Manifest
    #   - .repo folder
    #   - If build_directory is not empty, backup its content excluding tmp* and tmp-newlib* directories
    # TODO add function description
    # TODO add more verbose log
    from upgrade_oniro_utils import get_manifest_projects
    from datetime import datetime
    import tarfile

    backup_folders = [layer["path"] for layer in get_manifest_projects()] # add all manifest layers
    backup_folders.append(".repo")
    if build_directory.exists():
        for child in  build_directory.iterdir():
            if child.is_dir() and "tmp" not in child.name and child.name != "downloads":
                backup_folders.append(f"{build_directory.name}/{child.name}")
    
    archive_name = f"upgrade_oniro_backup-{datetime.timestamp(datetime.now())}.tar.gz"
    with tarfile.open(archive_name, "w:gz") as tar_archive:
        for folder in backup_folders:
            tar_archive.add(folder)
            print(f"{folder} has been backed up")
    
    return

def restore_oniro():
    # TODO
    return

def upgrade_oniro():
    # TODO
    return

if __name__ == "__main__":
    init_script_options()
    upgrade_tool()
    perform_pre_upgrade_checks()
    backup_oniro()
    upgrade_oniro()