blob: 9debbba026f17a148fee158a6653abb9ecaf7d98 [file] [log] [blame]
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A module for the init command."""
from __future__ import print_function
import os
import cr
# The set of variables to store in the per output configuration.
OUT_CONFIG_VARS = [
'CR_VERSION',
cr.Platform.SELECTOR,
cr.BuildType.SELECTOR,
cr.Arch.SELECTOR,
cr.PrepareOut.SELECTOR,
'CR_OUT_BASE',
'CR_OUT_FULL',
]
class InitCommand(cr.Command):
"""The implementation of the init command.
The init command builds or updates an output directory.
It then uses the Prepare and Select commands to get that directory
ready to use.
"""
def __init__(self):
super(InitCommand, self).__init__()
self.requires_build_dir = False
self.help = 'Create and configure an output directory'
self.description = ("""
If the .cr directory is not present, build it and add
the specified configuration.
If the file already exists, update the configuration with any
additional settings.
""")
self._settings = []
def AddArguments(self, subparsers):
"""Overridden from cr.Command."""
parser = super(InitCommand, self).AddArguments(subparsers)
cr.Platform.AddArguments(parser)
cr.BuildType.AddArguments(parser)
cr.Arch.AddArguments(parser)
cr.SelectCommand.AddPrepareArguments(parser)
cr.PrepareOut.AddArguments(parser)
parser.add_argument(
'-s', '--set', dest='_settings', metavar='settings',
action='append',
help='Configuration overrides.'
)
return parser
def EarlyArgProcessing(self):
base_settings = getattr(cr.context.args, '_settings', None)
if base_settings:
self._settings.extend(base_settings)
# Do not call super early processing, we do not want to apply
# the output arg...
out = cr.base.client.GetOutArgument()
if out:
# Output directory is fully specified
# We need to deduce other settings from it's name
base, buildtype = os.path.split(out)
if not (base and buildtype):
print('Specified output directory must be two levels')
exit(1)
if not cr.BuildType.FindPlugin(buildtype):
print('Specified build type', buildtype, 'is not valid')
print('Must be one of',
','.join(p.name for p in cr.BuildType.Plugins()))
exit(1)
if (cr.context.args.CR_BUILDTYPE and
cr.context.args.CR_BUILDTYPE != buildtype):
print('If --type and --out are both specified, they must match')
print('Got', cr.context.args.CR_BUILDTYPE, 'and', buildtype)
exit(1)
platform = cr.context.args.CR_PLATFORM
if not platform:
# Try to guess platform based on output name
platforms = [p.name for p in cr.Platform.AllPlugins()]
matches = [p for p in platforms if p in base]
# Get the longest matching string and check if the others are
# substrings. This is done to support "linuxchromeos" and "linux".
platform = max(matches, key=len)
all_matches_are_substrings = all(p in platform for p in matches)
if not all_matches_are_substrings or not matches:
print('Platform is not set, and could not be guessed from', base)
print('Should be one of', ','.join(platforms))
if len(matches) > 1:
print('Matched all of', ','.join(matches))
exit(1)
generator = cr.context.args.CR_GENERATOR
if not generator:
generator = 'gn'
cr.context.derived.Set(
CR_OUT_FULL=out,
CR_OUT_BASE=base,
CR_PLATFORM=platform,
CR_BUILDTYPE=buildtype,
CR_GENERATOR=generator
)
if not 'CR_OUT_BASE' in cr.context:
cr.context.derived['CR_OUT_BASE'] = 'out_{CR_PLATFORM}'
if not 'CR_OUT_FULL' in cr.context:
cr.context.derived['CR_OUT_FULL'] = os.path.join(
'{CR_OUT_BASE}', '{CR_BUILDTYPE}')
def Run(self):
"""Overridden from cr.Command."""
src_path = cr.context.Get('CR_SRC')
if not os.path.isdir(src_path):
print(cr.context.Substitute('Path {CR_SRC} is not a valid client'))
exit(1)
# Ensure we have an output directory override ready to fill in
# This will only be missing if we are creating a brand new output
# directory
build_package = cr.auto.build
# Collect the old version (and float convert)
old_version = cr.context.Find('CR_VERSION')
try:
old_version = float(old_version)
except (ValueError, TypeError):
old_version = 0.0
is_new = not hasattr(build_package, 'config')
if is_new:
class FakeModule(object):
OVERRIDES = cr.Config('OVERRIDES')
def __init__(self):
self.__name__ = 'config'
old_version = None
config = FakeModule()
setattr(build_package, 'config', config)
cr.plugin.ChainModuleConfigs(config)
# Force override the version
build_package.config.OVERRIDES.Set(CR_VERSION=cr.base.client.VERSION)
# Add all the variables that we always want to have
for name in OUT_CONFIG_VARS:
value = cr.context.Find(name)
build_package.config.OVERRIDES[name] = value
# Apply the settings from the command line
for setting in self._settings:
name, separator, value = setting.partition('=')
name = name.strip()
if not separator:
value = True
else:
value = cr.Config.ParseValue(value.strip())
build_package.config.OVERRIDES[name] = value
# Run all the output directory init hooks
for hook in cr.InitHook.Plugins():
hook.Run(old_version, build_package.config)
# Redo activations, they might have changed
cr.plugin.Activate()
# Write out the new configuration, and select it as the default
cr.base.client.WriteConfig(
use_build_dir=True, data=build_package.config.OVERRIDES.exported)
# Prepare the platform in here, using the updated config
cr.Platform.Prepare()
cr.SelectCommand.Select()