blob: d3c0fa0c1fe8348f48b0db9f21c6a8726e16a0b9 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2020 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""AP firmware utilities."""
from __future__ import print_function
import collections
import importlib
from chromite.lib import cros_build_lib
from chromite.lib import cros_logging as logging
from chromite.lib import workon_helper
from chromite.lib.firmware import flash_ap
_BUILD_TARGET_CONFIG_MODULE = 'chromite.lib.firmware.ap_firmware_config.%s'
_CONFIG_BUILD_WORKON_PACKAGES = 'BUILD_WORKON_PACKAGES'
_CONFIG_BUILD_PACKAGES = 'BUILD_PACKAGES'
# The build configs. The workon and build fields both contain tuples of
# packages.
BuildConfig = collections.namedtuple('BuildConfig', ('workon', 'build'))
class Error(Exception):
"""Base error class for the module."""
class BuildError(Error):
"""Failure in the build command."""
class BuildTargetNotConfiguredError(Error):
"""Thrown when a config module does not exist for the build target."""
class DeployError(Error):
"""Failure in the deploy command."""
class InvalidConfigError(Error):
"""The config does not contain the required information for the operation."""
def build(build_target):
"""Build the AP Firmware.
Args:
build_target (BuildTarget): The build target (board) being built.
"""
workon = workon_helper.WorkonHelper(build_target.root, build_target.name)
config = _get_build_config(build_target)
# Workon the required packages. Also calculate the list of packages that need
# to be stopped to clean up after ourselves when we're done.
if config.workon:
before_workon = workon.ListAtoms()
logging.info('cros_workon-%s start %s', build_target.name,
' '.join(config.workon))
workon.StartWorkingOnPackages(config.workon)
after_workon = workon.ListAtoms()
stop_packages = list(set(after_workon) - set(before_workon))
else:
stop_packages = []
# Run the emerge command to build the packages. Don't raise an exception here
# if it fails so we can cros workon stop afterwords.
result = cros_build_lib.run(
[build_target.get_command('emerge')] + list(config.build), check=False)
# Reset the environment.
if stop_packages:
# Stop the packages we started.
logging.info('cros_workon-%s stop %s', build_target.name,
' '.join(stop_packages))
workon.StopWorkingOnPackages(stop_packages)
else:
logging.info('No packages needed to be stopped.')
if result.returncode:
# Now raise the emerge failure since we're done cleaning up.
raise BuildError(
'The emerge command failed. See the logs above for details.')
def deploy(build_target,
image,
device,
flashrom=False,
fast=False,
verbose=False,
dryrun=False):
"""Deploy a firmware image to a device.
Args:
build_target (build_target_util.BuildTarget): The build target.
image (str): The path to the image to flash.
device (commandline.Device): The DUT being flashed.
flashrom (bool): Whether to use flashrom or futility.
fast (bool): Perform a faster flash that isn't validated.
verbose (bool): Whether to enable verbose output of the flash commands.
dryrun (bool): Whether to actually execute the deployment or just print the
operations that would have been performed.
"""
try:
flash_ap.deploy(
build_target=build_target,
image=image,
device=device,
flashrom=flashrom,
fast=fast,
verbose=verbose,
dryrun=dryrun)
except flash_ap.Error as e:
# Reraise as a DeployError for future compatibility.
raise DeployError(str(e))
def _get_build_config(build_target):
"""Get the relevant build config for |build_target|."""
module = _get_config_module(build_target)
workon_pkgs = getattr(module, _CONFIG_BUILD_WORKON_PACKAGES, None)
build_pkgs = getattr(module, _CONFIG_BUILD_PACKAGES, None)
if not build_pkgs:
raise InvalidConfigError(
'No packages specified to build in the configs for %s.' %
build_target.name)
return BuildConfig(workon=workon_pkgs, build=build_pkgs)
def _get_config_module(build_target):
"""Get the |build_target|'s config module."""
name = _BUILD_TARGET_CONFIG_MODULE % build_target.name
try:
return importlib.import_module(name)
except ImportError:
raise BuildTargetNotConfiguredError(
'Could not find a config module for %s.' % build_target.name)