blob: 68f413bc0ec3dd65ed177014fc68c095fe13d2cb [file] [log] [blame]
# Copyright 2015 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Utilities for updating and building in the chroot environment."""
import logging
import os
from chromite.third_party.opentelemetry import trace
from chromite.lib import constants
from chromite.lib import cros_build_lib
from chromite.lib import cros_sdk_lib
from chromite.lib import osutils
from chromite.lib import path_util
from chromite.lib import sysroot_lib
tracer = trace.get_tracer(__name__)
if cros_build_lib.IsInsideChroot():
# These import libraries outside chromite. See brbug.com/472.
from chromite.scripts import cros_list_modified_packages as workon
from chromite.scripts import cros_setup_toolchains as toolchain
_HOST_PKGS = (
"virtual/target-sdk",
"world",
)
_DEFAULT_MAKE_CONF_USER = """
# This file is useful for doing global (chroot and all board) changes.
# Tweak emerge settings, ebuild env, etc...
#
# Make sure to append variables unless you really want to clobber all
# existing settings. e.g. You most likely want:
# FEATURES="${FEATURES} ..."
# USE="${USE} foo"
# and *not*:
# USE="foo"
#
# This also is a good place to setup ACCEPT_LICENSE.
"""
def _GetToolchainPackages():
"""Get a list of host toolchain packages."""
# Load crossdev cache first for faster performance.
toolchain.Crossdev.Load(False)
packages = toolchain.GetTargetPackages("host")
return [toolchain.GetPortagePackage("host", x) for x in packages]
def GetEmergeCommand(sysroot=None):
"""Returns the emerge command to use for |sysroot| (host if None)."""
cmd = [constants.CHROMITE_BIN_DIR / "parallel_emerge"]
if sysroot and sysroot != "/":
cmd += ["--sysroot=%s" % sysroot]
return cmd
@tracer.start_as_current_span("chroot_util.Emerge")
def Emerge(
packages,
sysroot,
with_deps=True,
rebuild_deps=True,
use_binary=True,
jobs=None,
debug_output=False,
):
"""Emerge the specified |packages|.
Args:
packages: List of packages to emerge.
sysroot: Path to the sysroot in which to emerge.
with_deps: Whether to include dependencies.
rebuild_deps: Whether to rebuild dependencies.
use_binary: Whether to use binary packages.
jobs: Number of jobs to run in parallel.
debug_output: Emit debug level output.
Raises:
cros_build_lib.RunCommandError: If emerge returns an error.
"""
cros_build_lib.AssertInsideChroot()
span = trace.get_current_span()
span.set_attributes(
{
"sysroot": sysroot,
"packages": packages,
"with_deps": with_deps,
"rebuild_deps": rebuild_deps,
"use_binary": use_binary,
"jobs": jobs,
}
)
if not packages:
raise ValueError("No packages provided")
cmd = GetEmergeCommand(sysroot)
cmd.append("-uNv")
modified_packages = workon.ListModifiedWorkonPackages(
sysroot_lib.Sysroot(sysroot)
)
if modified_packages is not None:
mod_pkg_list = " ".join(modified_packages)
cmd += [
"--reinstall-atoms=" + mod_pkg_list,
"--usepkg-exclude=" + mod_pkg_list,
]
cmd.append("--deep" if with_deps else "--nodeps")
if use_binary:
cmd += ["-g", "--with-bdeps=y"]
if sysroot == "/":
# Only update toolchains in the chroot when binpkgs are available.
# The toolchain rollout process only takes place when the chromiumos
# sdk builder finishes a successful build and pushes out binpkgs.
cmd += ["--useoldpkg-atoms=%s" % " ".join(_GetToolchainPackages())]
if rebuild_deps:
cmd.append("--rebuild-if-unbuilt")
if jobs:
cmd.append("--jobs=%d" % jobs)
if debug_output:
cmd.append("--show-output")
# We might build chrome, in which case we need to pass 'CHROME_ORIGIN'.
cros_build_lib.sudo_run(cmd + packages, preserve_env=True)
def UpdateChroot(board=None, update_host_packages=True):
"""Update the chroot."""
# Run chroot update hooks.
logging.notice("Updating the chroot. This may take several minutes.")
cros_sdk_lib.RunChrootVersionHooks()
# Update toolchains.
cmd = [constants.CHROMITE_BIN_DIR / "cros_setup_toolchains"]
if board:
cmd += ["--targets=boards", "--include-boards=%s" % board]
cros_build_lib.sudo_run(cmd, debug_level=logging.DEBUG)
# Update the host before updating the board.
if update_host_packages:
Emerge(list(_HOST_PKGS), "/", rebuild_deps=False)
# Automatically discard all CONFIG_PROTECT'ed files. Those that are
# protected should not be overwritten until the variable is changed.
# Autodiscard is option "-9" followed by the "YES" confirmation.
cros_build_lib.sudo_run(
["etc-update"], input="-9\nYES\n", debug_level=logging.DEBUG
)
@tracer.start_as_current_span("chroot_util.RunUnittests")
def RunUnittests(
sysroot,
packages,
extra_env=None,
keep_going=False,
verbose=False,
retries=None,
jobs=None,
):
"""Runs the unit tests for |packages|.
Args:
sysroot: Path to the sysroot to build the tests in.
packages: List of packages to test.
extra_env: Python dictionary containing the extra environment variable
to pass to the build command.
keep_going: Tolerate package failure from parallel_emerge.
verbose: If True, show the output from emerge, even when the tests
succeed.
retries: Number of time we should retry a failed packages. If None, use
parallel_emerge's default.
jobs: Max number of parallel jobs. (optional)
Raises:
RunCommandError if the unit tests failed.
"""
span = trace.get_current_span()
span.set_attributes(
{
"sysroot": sysroot,
"packages": packages,
"keep_going": keep_going,
"retries": retries,
"jobs": jobs,
}
)
env = extra_env.copy() if extra_env else {}
if "FEATURES" in env:
env["FEATURES"] += " test"
else:
env["FEATURES"] = "test"
env["PKGDIR"] = os.path.join(sysroot, constants.UNITTEST_PKG_PATH)
command = [
constants.CHROMITE_BIN_DIR / "parallel_emerge",
"--sysroot=%s" % sysroot,
]
if keep_going:
command += ["--keep-going=y"]
if verbose:
command += ["--show-output"]
command += ["--verbose"]
if retries is not None:
command += ["--retries=%s" % retries]
if jobs is not None:
command += ["--jobs=%s" % jobs]
command += list(packages)
cros_build_lib.sudo_run(command, extra_env=env)
def CreateMakeConfUser():
"""Create default make.conf.user file in the chroot if it does not exist."""
path = "/etc/make.conf.user"
if not cros_build_lib.IsInsideChroot():
path = path_util.FromChrootPath(path)
if not os.path.exists(path):
osutils.WriteFile(path, _DEFAULT_MAKE_CONF_USER, sudo=True)