blob: c7b69e8f4e673570ecf4869c5920ae79508e74ce [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2015 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.
# TODO: Support cleaning /build/*/tmp.
# TODO: Support running `eclean -q packages` on / and the sysroots.
# TODO: Support cleaning sysroots as a destructive option.
"""Clean up working files in a Chromium OS checkout.
If unsure, just use the --safe flag to clean out various objects.
"""
from __future__ import print_function
import errno
import glob
import os
import sys
from chromite.lib import constants
from chromite.cli import command
from chromite.lib import cros_build_lib
from chromite.lib import cros_logging as logging
from chromite.lib import dev_server_wrapper
from chromite.lib import osutils
assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
@command.CommandDecorator('clean')
class CleanCommand(command.CliCommand):
"""Clean up working files from the build."""
@classmethod
def AddParser(cls, parser):
"""Add parser arguments."""
super(CleanCommand, cls).AddParser(parser)
parser.add_argument(
'--safe',
default=False,
action='store_true',
help='Clean up files that are automatically created.')
parser.add_argument(
'-n',
'--dry-run',
default=False,
action='store_true',
help='Show which paths would be cleaned up.')
group = parser.add_argument_group(
'Cache Selection (Advanced)',
description='Clean out specific caches (--safe does all of these).')
group.add_argument(
'--cache',
default=False,
action='store_true',
help='Clean up our shared cache dir.')
group.add_argument(
'--chromite',
default=False,
action='store_true',
help='Clean up chromite working directories.')
group.add_argument(
'--deploy',
default=False,
action='store_true',
help='Clean files cached by cros deploy.')
group.add_argument(
'--flash',
default=False,
action='store_true',
help='Clean files cached by cros flash.')
group.add_argument(
'--images',
default=False,
action='store_true',
help='Clean up locally generated images.')
group.add_argument(
'--incrementals',
default=False,
action='store_true',
help='Clean up incremental package objects.')
group.add_argument(
'--logs',
default=False,
action='store_true',
help='Clean up various build log files.')
group.add_argument(
'--workdirs',
default=False,
action='store_true',
help='Clean up build various package build directories.')
group.add_argument(
'--chroot-tmp',
default=False,
action='store_true',
help="Empty the chroot's /tmp directory.")
group = parser.add_argument_group(
'Unrecoverable Options (Dangerous)',
description='Clean out objects that cannot be recovered easily.')
group.add_argument(
'--clobber',
default=False,
action='store_true',
help='Delete all non-source objects.')
group.add_argument(
'--chroot',
default=False,
action='store_true',
help='Delete build chroot (affects all boards).')
group.add_argument(
'--board', action='append', help='Delete board(s) sysroot(s).')
group.add_argument(
'--sysroots',
default=False,
action='store_true',
help='Delete ALL of the sysroots. This is the same as calling with '
'--board with every board that has been built.')
group.add_argument(
'--autotest',
default=False,
action='store_true',
help='Delete build_externals packages.')
group = parser.add_argument_group(
'Advanced Customization',
description='Advanced options that are rarely be needed.')
group.add_argument(
'--sdk-path',
type='path',
default=os.path.join(constants.SOURCE_ROOT,
constants.DEFAULT_CHROOT_DIR),
help='The sdk (chroot) path. This only needs to be provided if your '
'chroot is not in the default location.')
def __init__(self, options):
"""Initializes cros clean."""
command.CliCommand.__init__(self, options)
def Run(self):
"""Perform the cros clean command."""
# If no option is set, default to "--safe"
if not (self.options.safe or self.options.clobber or self.options.board or
self.options.chroot or self.options.cache or self.options.deploy or
self.options.flash or self.options.images or
self.options.autotest or self.options.incrementals or
self.options.chroot_tmp or self.options.sysroots):
self.options.safe = True
if self.options.clobber:
self.options.chroot = True
self.options.autotest = True
self.options.safe = True
if self.options.safe:
self.options.cache = True
self.options.chromite = True
self.options.chroot_tmp = True
self.options.deploy = True
self.options.flash = True
self.options.images = True
self.options.incrementals = True
self.options.logs = True
self.options.workdirs = True
self.options.Freeze()
chroot_dir = self.options.sdk_path
cros_build_lib.AssertOutsideChroot()
def _LogClean(path):
logging.notice('would have cleaned: %s', path)
def Clean(path):
"""Helper wrapper for the dry-run checks"""
if self.options.dry_run:
_LogClean(path)
else:
osutils.RmDir(path, ignore_missing=True, sudo=True)
def Empty(path):
"""Helper wrapper for the dry-run checks"""
if self.options.dry_run:
logging.notice('would have emptied: %s', path)
else:
osutils.EmptyDir(path, ignore_missing=True, sudo=True)
def CleanNoBindMount(path):
# This test is a convenience for developers that bind mount these dirs.
if not os.path.ismount(path):
Clean(path)
else:
logging.debug('Ignoring bind mounted dir: %s', path)
# Delete this first since many of the caches below live in the chroot.
if self.options.chroot:
logging.debug('Remove the chroot.')
if self.options.dry_run:
logging.notice('would have cleaned: %s', chroot_dir)
else:
cros_build_lib.run(['cros_sdk', '--delete'])
boards = self.options.board or []
if self.options.sysroots:
try:
boards = os.listdir(os.path.join(chroot_dir, 'build'))
except OSError as e:
if e.errno != errno.ENOENT:
raise
for b in boards:
logging.debug('Clean up the %s sysroot.', b)
Clean(os.path.join(chroot_dir, 'build', b))
if self.options.chroot_tmp:
logging.debug('Empty chroot tmp directory.')
Empty(os.path.join(chroot_dir, 'tmp'))
if self.options.cache:
logging.debug('Clean the common cache.')
CleanNoBindMount(self.options.cache_dir)
# Recreate dirs that cros_sdk does when entering.
# TODO: When sdk_lib/enter_chroot.sh is moved to chromite, we should unify
# with those code paths.
if not self.options.dry_run:
for subdir in ('ccache', 'host', 'target'):
osutils.SafeMakedirs(
os.path.join(self.options.cache_dir, 'distfiles', subdir))
os.chmod(
os.path.join(self.options.cache_dir, 'distfiles', 'ccache'), 0o2775)
if self.options.chromite:
logging.debug('Clean chromite workdirs.')
Clean(os.path.join(constants.CHROMITE_DIR, 'venv', 'venv'))
Clean(os.path.join(constants.CHROMITE_DIR, 'venv', '.venv_lock'))
if self.options.deploy:
logging.debug('Clean up the cros deploy cache.')
for subdir in ('custom-packages', 'gmerge-packages'):
for d in glob.glob(os.path.join(chroot_dir, 'build', '*', subdir)):
Clean(d)
if self.options.flash:
if self.options.dry_run:
_LogClean(dev_server_wrapper.DEFAULT_STATIC_DIR)
else:
dev_server_wrapper.DevServerWrapper.WipeStaticDirectory()
if self.options.images:
logging.debug('Clean the images cache.')
cache_dir = os.path.join(constants.SOURCE_ROOT, 'src', 'build')
CleanNoBindMount(cache_dir)
if self.options.incrementals:
logging.debug('Clean package incremental objects.')
Clean(os.path.join(chroot_dir, 'var', 'cache', 'portage'))
for d in glob.glob(
os.path.join(chroot_dir, 'build', '*', 'var', 'cache', 'portage')):
Clean(d)
if self.options.logs:
logging.debug('Clean log files.')
Clean(os.path.join(chroot_dir, 'var', 'log'))
for d in glob.glob(
os.path.join(chroot_dir, 'build', '*', 'tmp', 'portage', 'logs')):
Clean(d)
if self.options.workdirs:
logging.debug('Clean package workdirs.')
Clean(os.path.join(chroot_dir, 'var', 'tmp', 'portage'))
Clean(os.path.join(constants.CHROMITE_DIR, 'venv', 'venv'))
for d in glob.glob(
os.path.join(chroot_dir, 'build', '*', 'tmp', 'portage')):
Clean(d)
if self.options.autotest:
logging.debug('Clean build_externals.')
packages_dir = os.path.join(constants.SOURCE_ROOT, 'src', 'third_party',
'autotest', 'files', 'site-packages')
Clean(packages_dir)