summaryrefslogtreecommitdiffstats
path: root/tools/cr/cr/commands/init.py
blob: 04692bae6cbff91728918c4e7f0677cd75288f27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# 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."""

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 = 'gyp'
      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()