blob: a8ac392a0580673d055bdf398ec1fea901ceded6 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2019 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.
"""Operations to work with the SDK chroot."""
from __future__ import print_function
import os
from chromite.lib import constants
from chromite.lib import cros_build_lib
from chromite.lib import cros_logging as logging
from chromite.lib import cros_sdk_lib
class ChrootPaths(object):
"""Value object to hold common cros_sdk path arguments."""
def __init__(self, cache_dir=None, chroot_path=None):
"""Chroot paths init.
Args:
cache_dir (str): Override the default cache directory.
chroot_path (str): Set the path the chroot resides (or will be created).
"""
self.cache_dir = cache_dir
self.chroot_path = chroot_path
def GetArgList(self):
"""Get the list of the corresponding commandline arguments.
Returns:
list - The list of the corresponding command line arguments.
"""
args = []
if self.cache_dir:
args.extend(['--cache-dir', self.cache_dir])
if self.chroot_path:
args.extend(['--chroot', self.chroot_path])
return args
class CreateArguments(object):
"""Value object to handle the chroot creation arguments."""
def __init__(self, replace=False, bootstrap=False, use_image=True,
paths=None):
"""Create arguments init.
Args:
replace (bool): Whether an existing chroot should be deleted.
bootstrap (bool): Whether to build the SDK from source.
use_image (bool): Whether to mount the chroot on a loopback image or
create it directly in a directory.
paths (ChrootPaths): Path arguments.
"""
self.replace = replace
self.bootstrap = bootstrap
self.use_image = use_image
self.paths = paths or ChrootPaths()
def GetArgList(self):
"""Get the list of the corresponding command line arguments.
Returns:
list - The list of the corresponding command line arguments.
"""
args = []
if self.replace:
args.append('--replace')
else:
args.append('--create')
if self.bootstrap:
args.append('--bootstrap')
if not self.use_image:
args.append('--nouse-image')
args.extend(self.paths.GetArgList())
return args
@property
def chroot_path(self):
return self.paths.chroot_path
class UpdateArguments(object):
"""Value object to handle the update arguments."""
def __init__(self,
build_source=False,
toolchain_targets=None,
toolchain_changed=False):
"""Update arguments init.
Args:
build_source (bool): Whether to build the source or use prebuilts.
toolchain_targets (list): The list of build targets whose toolchains
should be updated.
toolchain_changed (bool): Whether a toolchain change has occurred. Implies
build_source.
"""
self.build_source = build_source or toolchain_changed
self.toolchain_targets = toolchain_targets
def GetArgList(self):
"""Get the list of the corresponding command line arguments.
Returns:
list - The list of the corresponding command line arguments.
"""
args = []
if self.build_source:
args.append('--nousepkg')
if self.toolchain_targets:
if not self.build_source:
args.extend(['--toolchain_boards', ','.join(self.toolchain_targets)])
else:
args.append('--skip_toolchain_update')
return args
def Clean(chroot, images=False, sysroots=False, tmp=False):
"""Clean the chroot.
See:
cros clean -h
Args:
chroot: The chroot to clean.
images (bool): Remove all built images.
sysroots (bool): Remove all of the sysroots.
tmp (bool): Clean the tmp/ directory.
"""
if not images and not sysroots and not tmp:
return
cmd = ['cros', 'clean']
if chroot:
cmd.extend(['--sdk-path', chroot.path])
if images:
cmd.append('--images')
if sysroots:
cmd.append('--sysroots')
if tmp:
cmd.append('--chroot-tmp')
cros_build_lib.run(cmd)
def Create(arguments):
"""Create or replace the chroot.
Args:
arguments (CreateArguments): The various arguments to create a chroot.
Returns:
int - The version of the resulting chroot.
"""
cros_build_lib.AssertOutsideChroot()
cmd = [os.path.join(constants.CHROMITE_BIN_DIR, 'cros_sdk')]
cmd.extend(arguments.GetArgList())
cros_build_lib.run(cmd)
version = GetChrootVersion(arguments.chroot_path)
if not arguments.replace:
# Force replace scenarios. Only needed when we're not already replacing it.
if not version:
# Force replace when we can't get a version for a chroot that exists,
# since something must have gone wrong.
logging.notice('Replacing broken chroot.')
arguments.replace = True
return Create(arguments)
elif not cros_sdk_lib.IsChrootVersionValid(arguments.chroot_path):
# Force replace when the version is not valid, i.e. ahead of the chroot
# version hooks.
logging.notice('Replacing chroot ahead of current checkout.')
arguments.replace = True
return Create(arguments)
elif not cros_sdk_lib.IsChrootDirValid(arguments.chroot_path):
# Force replace when the permissions or owner are not correct.
logging.notice('Replacing chroot with invalid permissions.')
arguments.replace = True
return Create(arguments)
return GetChrootVersion(arguments.chroot_path)
def Delete(chroot=None):
"""Delete the chroot.
Args:
chroot (chroot_lib.Chroot): The chroot being deleted, or None for the
default chroot.
"""
# Manually remove the sysroots to reduce the time taken to delete the chroot.
logging.info('Removing sysroots.')
Clean(chroot, sysroots=True)
# Delete the chroot itself.
logging.info('Removing the SDK.')
cmd = [os.path.join(constants.CHROMITE_BIN_DIR, 'cros_sdk'), '--delete']
if chroot:
cmd.extend(['--chroot', chroot.path])
cros_build_lib.run(cmd)
# Remove any images that were built.
logging.info('Removing images.')
Clean(chroot, images=True)
def Unmount(chroot=None):
"""Unmount the chroot.
Args:
chroot (chroot_lib.Chroot): The chroot being unmounted, or None for the
default chroot.
"""
logging.info('Unmounting the chroot.')
cmd = [os.path.join(constants.CHROMITE_BIN_DIR, 'cros_sdk'), '--unmount']
if chroot:
cmd.extend(['--chroot', chroot.path])
cros_build_lib.run(cmd)
def GetChrootVersion(chroot_path=None):
"""Get the chroot version.
Args:
chroot_path (str|None): The chroot path.
Returns:
int|None - The version of the chroot if the chroot is valid, else None.
"""
if chroot_path:
path = chroot_path
elif cros_build_lib.IsInsideChroot():
path = None
else:
path = constants.DEFAULT_CHROOT_PATH
return cros_sdk_lib.GetChrootVersion(path)
def Update(arguments):
"""Update the chroot.
Args:
arguments (UpdateArguments): The various arguments for updating a chroot.
Returns:
int - The version of the chroot after the update.
"""
# TODO: This should be able to be run either in or out of the chroot.
cros_build_lib.AssertInsideChroot()
cmd = [os.path.join(constants.CROSUTILS_DIR, 'update_chroot')]
cmd.extend(arguments.GetArgList())
# The sdk update uses splitdebug instead of separatedebug. Make sure
# separatedebug is disabled and enable splitdebug.
existing = os.environ.get('FEATURES', '')
features = ' '.join((existing, '-separatedebug splitdebug')).strip()
extra_env = {'FEATURES': features}
cros_build_lib.run(cmd, extra_env=extra_env)
return GetChrootVersion()