blob: 06032b3be496853db14a2ef3ed267e2dcd3656e0 [file] [log] [blame]
# Copyright 2018 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Script to generate a DLC (Downloadable Content) artifact."""
import logging
from chromite.lib import commandline
from chromite.lib import dlc_lib
def GetParser():
"""Creates an argument parser and returns it."""
parser = commandline.ArgumentParser(description=__doc__)
# This script is used both for building an individual DLC or copying all
# final DLCs images to their final destination nearby
# chromiumos_test_image.bin, etc. These two arguments are required in both
# cases.
parser.add_argument(
"--sysroot",
type="str_path",
metavar="DIR",
help="The root path to the board's build root, e.g. /build/eve",
)
# TODO(andrewlassalle): Remove src-dir in the future(2021?) if nobody uses
# it.
parser.add_argument(
"--src-dir",
type="str_path",
metavar="SRC_DIR_PATH",
help=(
"Override the default Root directory path that contains all DLC "
"files to be packed."
),
)
parser.add_argument(
"--install-root-dir",
type="str_path",
metavar="DIR",
help=(
"If building a specific DLC, it is the root path to"
" install DLC images (%s) and metadata (%s). Otherwise it"
" is the target directory where the Chrome OS images gets"
" dropped in `cros build-image`, e.g. "
"src/build/images/<board>/latest."
)
% (dlc_lib.DLC_BUILD_DIR, dlc_lib.DLC_META_DIR),
)
one_dlc = parser.add_argument_group(
"Arguments required for building only one DLC"
)
one_dlc.add_argument(
"--rootfs",
type="str_path",
metavar="ROOT_FS_PATH",
help="Path to the platform rootfs.",
)
one_dlc.add_argument(
"--stateful",
type="str_path",
metavar="STATEFUL_PATH",
help="Path to the platform stateful.",
)
one_dlc.add_argument(
"--pre-allocated-blocks",
type=int,
metavar="PREALLOCATEDBLOCKS",
help=(
"Number of blocks (block size is 4k) that need to"
"be pre-allocated on device."
),
)
one_dlc.add_argument("--version", metavar="VERSION", help="DLC Version.")
one_dlc.add_argument("--id", metavar="ID", help="DLC ID (unique per DLC).")
one_dlc.add_argument(
"--package",
metavar="PACKAGE",
help=(
"The package ID that is unique within a DLC, One"
" DLC cannot have duplicate package IDs."
),
)
one_dlc.add_argument(
"--name", metavar="NAME", help="A human-readable name for the DLC."
)
one_dlc.add_argument("--description", help="The description for the DLC.")
one_dlc.add_argument(
"--board", metavar="BOARD", help="The target board we are building for."
)
one_dlc.add_argument(
"--fullnamerev",
metavar="FULL_NAME_REV",
help="The full ebuild package name.",
)
one_dlc.add_argument(
"--fs-type",
metavar="FS_TYPE",
default=dlc_lib.SQUASHFS_TYPE,
choices=(dlc_lib.SQUASHFS_TYPE, dlc_lib.EXT2_TYPE, dlc_lib.EXT4_TYPE),
help="File system type of the image.",
)
one_dlc.add_argument(
"--preload",
default=False,
action="store_true",
help="Allow preloading of DLC.",
)
one_dlc.add_argument(
"--factory-install",
default=False,
action="store_true",
help="Allow factory installing of DLC.",
)
one_dlc.add_argument(
"--loadpin-verity-digest",
default=False,
action="store_true",
help="Allow DLC to be a trusted dm-verity digest.",
)
one_dlc.add_argument(
"--mount-file-required",
default=False,
action="store_true",
help="Allow indirect mount file generation for DLC.",
)
one_dlc.add_argument(
"--scaled",
default=False,
action="store_true",
help="DLC will be fed through scaling design.",
)
one_dlc.add_argument(
"--force-ota",
default=False,
action="store_true",
help="DLC will allow forced OTA installations.",
)
one_dlc.add_argument(
"--reserved",
default=False,
action="store_true",
help="Always reserve space for this DLC.",
)
one_dlc.add_argument(
"--critical-update",
default=False,
action="store_true",
help="Always update with the OS for this DLC.",
)
one_dlc.add_argument(
"--build-package",
default=False,
action="store_true",
help=(
"Flag to indicate if the script is executed during the "
"`cros build-packages` phase."
),
)
one_dlc.add_argument(
"--powerwash-safe",
default=False,
action="store_true",
help="DLC will be powerwash safe. (Only on LVM supported devices)",
)
# Arguments groups don't support `add_bool_argument` yet.
one_dlc.add_argument(
"--use-logical-volume",
default=False,
action="store_true",
help="DLC will use logical volumes on LVM stateful partition "
"migrated devices. (scaled option takes precedence)",
)
one_dlc.add_argument(
"--user-tied",
default=False,
action="store_true",
help="DLC will be user-tied.",
)
return parser
def ValidateArguments(parser, opts, req_flags, invalid_flags) -> None:
"""Validates the correctness of the passed arguments.
Args:
parser: Arguments parser.
opts: Parsed arguments.
req_flags: all the required flags.
invalid_flags: all the flags that are not allowed.
"""
# Make sure if the intention is to build one DLC, all the required arguments
# are passed and none of the invalid ones are passed. This will ensure the
# script is called twice per DLC.
if opts.id:
if not all(vars(opts)[x] is not None for x in req_flags):
parser.error(
"If the intention is to build only one DLC, all the flags"
"%s required for it should be passed." % req_flags
)
if any(vars(opts)[x] is not None for x in invalid_flags):
parser.error(
"If the intention is to build only one DLC, all the flags"
"%s should be passed in the `cros build-packages` phase, not "
"in the `cros build-image` phase." % invalid_flags
)
if opts.fs_type not in (
dlc_lib.EXT2_TYPE,
dlc_lib.EXT4_TYPE,
dlc_lib.SQUASHFS_TYPE,
):
parser.error(
"Unsupported filesystem type (%s) given for DLC." % opts.fs_type
)
if opts.id:
dlc_lib.ValidateDlcIdentifier(opts.id)
if opts.package:
dlc_lib.ValidateDlcIdentifier(opts.package)
def main(argv) -> None:
parser = GetParser()
opts = parser.parse_args(argv)
opts.Freeze()
per_dlc_req_args = ["id"]
per_dlc_invalid_args = []
if opts.build_package:
per_dlc_req_args += [
"pre_allocated_blocks",
"version",
"name",
"description",
"package",
"install_root_dir",
]
per_dlc_invalid_args += ["src_dir", "sysroot", "stateful"]
else:
per_dlc_req_args += ["sysroot", "board"]
per_dlc_invalid_args += [
"name",
"pre_allocated_blocks",
"version",
"package",
"reserved",
"critical_update",
]
ValidateArguments(parser, opts, per_dlc_req_args, per_dlc_invalid_args)
if opts.build_package:
logging.info("Building package: DLC %s", opts.id)
params = dlc_lib.EbuildParams(
dlc_id=opts.id,
dlc_package=opts.package,
fs_type=opts.fs_type,
name=opts.name,
description=opts.description,
pre_allocated_blocks=opts.pre_allocated_blocks,
version=opts.version,
preload=opts.preload,
factory_install=opts.factory_install,
loadpin_verity_digest=opts.loadpin_verity_digest,
mount_file_required=opts.mount_file_required,
reserved=opts.reserved,
critical_update=opts.critical_update,
fullnamerev=opts.fullnamerev,
scaled=opts.scaled,
force_ota=opts.force_ota,
powerwash_safe=opts.powerwash_safe,
use_logical_volume=opts.use_logical_volume,
user_tied=opts.user_tied,
)
params.VerifyDlcParameters()
params.StoreDlcParameters(
install_root_dir=opts.install_root_dir, sudo=True
)
else:
dlc_lib.InstallDlcImages(
sysroot=opts.sysroot,
dlc_id=opts.id,
install_root_dir=opts.install_root_dir,
preload=opts.preload,
factory_install=opts.factory_install,
src_dir=opts.src_dir,
rootfs=opts.rootfs,
stateful=opts.stateful,
board=opts.board,
)