xref: /aosp_15_r20/tools/treble/build/sandbox/config.py (revision 105f628577ac4ba0e277a494fbb614ed8c12a994)
1*105f6285SAndroid Build Coastguard Worker# Copyright 2020 Google LLC
2*105f6285SAndroid Build Coastguard Worker#
3*105f6285SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*105f6285SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*105f6285SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*105f6285SAndroid Build Coastguard Worker#
7*105f6285SAndroid Build Coastguard Worker#     https://www.apache.org/licenses/LICENSE-2.0
8*105f6285SAndroid Build Coastguard Worker#
9*105f6285SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*105f6285SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*105f6285SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*105f6285SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*105f6285SAndroid Build Coastguard Worker# limitations under the License.
14*105f6285SAndroid Build Coastguard Worker"""Parses config file and provides various ways of using it."""
15*105f6285SAndroid Build Coastguard Worker
16*105f6285SAndroid Build Coastguard Workerimport xml.etree.ElementTree as ET
17*105f6285SAndroid Build Coastguard Workerimport collections
18*105f6285SAndroid Build Coastguard Worker
19*105f6285SAndroid Build Coastguard Worker# The config file must be in XML with a structure as descibed below.
20*105f6285SAndroid Build Coastguard Worker#
21*105f6285SAndroid Build Coastguard Worker# The top level config element shall contain one or more "target" child
22*105f6285SAndroid Build Coastguard Worker# elements. Each of these may contain one or more build_config child elements.
23*105f6285SAndroid Build Coastguard Worker# The build_config child elements will inherit the properties of the target
24*105f6285SAndroid Build Coastguard Worker# parent.
25*105f6285SAndroid Build Coastguard Worker#
26*105f6285SAndroid Build Coastguard Worker# Each "target" and "build_config" may contain the following:
27*105f6285SAndroid Build Coastguard Worker#
28*105f6285SAndroid Build Coastguard Worker# Attributes:
29*105f6285SAndroid Build Coastguard Worker#
30*105f6285SAndroid Build Coastguard Worker#   name: The name of the target.
31*105f6285SAndroid Build Coastguard Worker#
32*105f6285SAndroid Build Coastguard Worker#   android_target: The name of the android target used with lunch
33*105f6285SAndroid Build Coastguard Worker#
34*105f6285SAndroid Build Coastguard Worker#   allow_readwrite_all: "true" if the full source folder shall be mounted as
35*105f6285SAndroid Build Coastguard Worker#   read/write. It should be accompanied by a comment with the bug describing
36*105f6285SAndroid Build Coastguard Worker#   why it was required.
37*105f6285SAndroid Build Coastguard Worker#
38*105f6285SAndroid Build Coastguard Worker#   tags: A comma-separated list of strings to be associated with the target
39*105f6285SAndroid Build Coastguard Worker#     and any of its nested build_targets. You can use a tag to associate
40*105f6285SAndroid Build Coastguard Worker#     information with a target in your configuration file, and retrieve that
41*105f6285SAndroid Build Coastguard Worker#     information using the get_tags API or the has_tag API.
42*105f6285SAndroid Build Coastguard Worker#
43*105f6285SAndroid Build Coastguard Worker# Child elements:
44*105f6285SAndroid Build Coastguard Worker#
45*105f6285SAndroid Build Coastguard Worker#   config: A generic name-value configuration element.
46*105f6285SAndroid Build Coastguard Worker#
47*105f6285SAndroid Build Coastguard Worker#     Attributes:
48*105f6285SAndroid Build Coastguard Worker#       name: Name of the configuration
49*105f6285SAndroid Build Coastguard Worker#       value: Value of the configuration
50*105f6285SAndroid Build Coastguard Worker#
51*105f6285SAndroid Build Coastguard Worker#   overlay: An overlay to be mounted while building the target.
52*105f6285SAndroid Build Coastguard Worker#
53*105f6285SAndroid Build Coastguard Worker#     Attributes:
54*105f6285SAndroid Build Coastguard Worker#
55*105f6285SAndroid Build Coastguard Worker#       name: The name of the overlay.
56*105f6285SAndroid Build Coastguard Worker#
57*105f6285SAndroid Build Coastguard Worker#     Child elements:
58*105f6285SAndroid Build Coastguard Worker#
59*105f6285SAndroid Build Coastguard Worker#       replacement_path:  An overlay path that supersedes any conflicts
60*105f6285SAndroid Build Coastguard Worker#         after it.
61*105f6285SAndroid Build Coastguard Worker#
62*105f6285SAndroid Build Coastguard Worker#         Properties:
63*105f6285SAndroid Build Coastguard Worker#
64*105f6285SAndroid Build Coastguard Worker#           name: The name of the replacement path. This path will will
65*105f6285SAndroid Build Coastguard Worker#             superced the same path for any subsequent conflicts. If two
66*105f6285SAndroid Build Coastguard Worker#             overlays have the same replacement path an error will occur.
67*105f6285SAndroid Build Coastguard Worker#
68*105f6285SAndroid Build Coastguard Worker#
69*105f6285SAndroid Build Coastguard Worker#   view: A map (optionally) specifying a filesystem view mapping for each
70*105f6285SAndroid Build Coastguard Worker#     target.
71*105f6285SAndroid Build Coastguard Worker#
72*105f6285SAndroid Build Coastguard Worker#     Attributes:
73*105f6285SAndroid Build Coastguard Worker#
74*105f6285SAndroid Build Coastguard Worker#       name: The name of the view.
75*105f6285SAndroid Build Coastguard Worker#
76*105f6285SAndroid Build Coastguard Worker#   allow_readwrite: A folder to mount read/write
77*105f6285SAndroid Build Coastguard Worker#   inside the Android build nsjail. Each allowed read-write entry should be
78*105f6285SAndroid Build Coastguard Worker#   accompanied by a bug that indicates why it was required and tracks the
79*105f6285SAndroid Build Coastguard Worker#   progress to a fix.
80*105f6285SAndroid Build Coastguard Worker#
81*105f6285SAndroid Build Coastguard Worker#     Attributes:
82*105f6285SAndroid Build Coastguard Worker#
83*105f6285SAndroid Build Coastguard Worker#       path: The path to be allowed read-write mounting.
84*105f6285SAndroid Build Coastguard Worker#
85*105f6285SAndroid Build Coastguard Worker#   build_config: A list of goals to be used while building the target.
86*105f6285SAndroid Build Coastguard Worker#
87*105f6285SAndroid Build Coastguard Worker#     Attributes:
88*105f6285SAndroid Build Coastguard Worker#
89*105f6285SAndroid Build Coastguard Worker#       name: The name of the build config. Defaults to the target name
90*105f6285SAndroid Build Coastguard Worker#         if not set.
91*105f6285SAndroid Build Coastguard Worker#
92*105f6285SAndroid Build Coastguard Worker#     Child elements:
93*105f6285SAndroid Build Coastguard Worker#
94*105f6285SAndroid Build Coastguard Worker#       goal: A build goal.
95*105f6285SAndroid Build Coastguard Worker#
96*105f6285SAndroid Build Coastguard Worker#         Properties:
97*105f6285SAndroid Build Coastguard Worker#
98*105f6285SAndroid Build Coastguard Worker#           name: The name of the build goal. The build tools pass the name
99*105f6285SAndroid Build Coastguard Worker#             attribute as a parameter to make. This can have a value like
100*105f6285SAndroid Build Coastguard Worker#             "droid" or "VAR=value".
101*105f6285SAndroid Build Coastguard Worker#
102*105f6285SAndroid Build Coastguard Worker#           contexts: A comma-separated list of the contexts in which this
103*105f6285SAndroid Build Coastguard Worker#             goal applies. If this attribute is missing or blank, the goal
104*105f6285SAndroid Build Coastguard Worker#             applies to all contexts. Otherwise, it applies only in the
105*105f6285SAndroid Build Coastguard Worker#             requested contexts (see get_build_goals).
106*105f6285SAndroid Build Coastguard Worker
107*105f6285SAndroid Build Coastguard WorkerOverlay = collections.namedtuple('Overlay', ['name', 'replacement_paths'])
108*105f6285SAndroid Build Coastguard Worker
109*105f6285SAndroid Build Coastguard Worker
110*105f6285SAndroid Build Coastguard Workerclass BuildConfig(object):
111*105f6285SAndroid Build Coastguard Worker  """Represents configuration of a build_target.
112*105f6285SAndroid Build Coastguard Worker
113*105f6285SAndroid Build Coastguard Worker  Attributes:
114*105f6285SAndroid Build Coastguard Worker    name: name of the build_target used to pull the configuration.
115*105f6285SAndroid Build Coastguard Worker    android_target: The name of the android target used with lunch.
116*105f6285SAndroid Build Coastguard Worker    tags: List of tags associated with the build target config
117*105f6285SAndroid Build Coastguard Worker    build_goals: List of goals to be used while building the target.
118*105f6285SAndroid Build Coastguard Worker    overlays: List of overlays to be mounted.
119*105f6285SAndroid Build Coastguard Worker    views: A list of (source, destination) string path tuple to be mounted. See
120*105f6285SAndroid Build Coastguard Worker      view nodes in XML.
121*105f6285SAndroid Build Coastguard Worker    allow_readwrite_all: If true, mount source tree as rw.
122*105f6285SAndroid Build Coastguard Worker    allow_readwrite: List of directories to be mounted as rw.
123*105f6285SAndroid Build Coastguard Worker    allowed_projects_file: a string path name of a file with a containing
124*105f6285SAndroid Build Coastguard Worker      allowed projects.
125*105f6285SAndroid Build Coastguard Worker    configurations: a map of name to value configurations
126*105f6285SAndroid Build Coastguard Worker  """
127*105f6285SAndroid Build Coastguard Worker
128*105f6285SAndroid Build Coastguard Worker  def __init__(self,
129*105f6285SAndroid Build Coastguard Worker               name,
130*105f6285SAndroid Build Coastguard Worker               android_target,
131*105f6285SAndroid Build Coastguard Worker               tags=frozenset(),
132*105f6285SAndroid Build Coastguard Worker               build_goals=(),
133*105f6285SAndroid Build Coastguard Worker               build_flags=(),
134*105f6285SAndroid Build Coastguard Worker               overlays=(),
135*105f6285SAndroid Build Coastguard Worker               views=(),
136*105f6285SAndroid Build Coastguard Worker               allow_readwrite_all=False,
137*105f6285SAndroid Build Coastguard Worker               allow_readwrite=(),
138*105f6285SAndroid Build Coastguard Worker               allowed_projects_file=None,
139*105f6285SAndroid Build Coastguard Worker               configurations=None):
140*105f6285SAndroid Build Coastguard Worker    super().__init__()
141*105f6285SAndroid Build Coastguard Worker    self.name = name
142*105f6285SAndroid Build Coastguard Worker    self.android_target = android_target
143*105f6285SAndroid Build Coastguard Worker    self.tags = tags
144*105f6285SAndroid Build Coastguard Worker    self.build_goals = list(build_goals)
145*105f6285SAndroid Build Coastguard Worker    self.build_flags = list(build_flags)
146*105f6285SAndroid Build Coastguard Worker    self.overlays = list(overlays)
147*105f6285SAndroid Build Coastguard Worker    self.views = list(views)
148*105f6285SAndroid Build Coastguard Worker    self.allow_readwrite_all = allow_readwrite_all
149*105f6285SAndroid Build Coastguard Worker    self.allow_readwrite = list(allow_readwrite)
150*105f6285SAndroid Build Coastguard Worker    self.allowed_projects_file = allowed_projects_file
151*105f6285SAndroid Build Coastguard Worker    self.configurations = configurations or {}
152*105f6285SAndroid Build Coastguard Worker
153*105f6285SAndroid Build Coastguard Worker  def validate(self):
154*105f6285SAndroid Build Coastguard Worker    """Run tests to validate build configuration"""
155*105f6285SAndroid Build Coastguard Worker    if not self.name:
156*105f6285SAndroid Build Coastguard Worker      raise ValueError('Error build_config must have a name.')
157*105f6285SAndroid Build Coastguard Worker    # Validate that a build config does not contain an overlay with
158*105f6285SAndroid Build Coastguard Worker    # conflicting replacement paths.
159*105f6285SAndroid Build Coastguard Worker    if len(self.overlays) > 1 and set.intersection(
160*105f6285SAndroid Build Coastguard Worker        *[o.replacement_paths for o in self.overlays]):
161*105f6285SAndroid Build Coastguard Worker      raise ValueError(
162*105f6285SAndroid Build Coastguard Worker          'Error build_config overlays have conflicting replacement_paths.')
163*105f6285SAndroid Build Coastguard Worker
164*105f6285SAndroid Build Coastguard Worker  @classmethod
165*105f6285SAndroid Build Coastguard Worker  def from_config(cls, config_elem, fs_view_map, base_config=None):
166*105f6285SAndroid Build Coastguard Worker    """Creates a BuildConfig from a config XML element and an optional base_config.
167*105f6285SAndroid Build Coastguard Worker
168*105f6285SAndroid Build Coastguard Worker    Args:
169*105f6285SAndroid Build Coastguard Worker      config_elem: the config XML node element to build the configuration
170*105f6285SAndroid Build Coastguard Worker      fs_view_map: A map of view names to list of tuple(source, destination)
171*105f6285SAndroid Build Coastguard Worker        paths.
172*105f6285SAndroid Build Coastguard Worker      base_config: the base BuildConfig to use
173*105f6285SAndroid Build Coastguard Worker
174*105f6285SAndroid Build Coastguard Worker    Returns:
175*105f6285SAndroid Build Coastguard Worker      A build config generated from the config element and the base
176*105f6285SAndroid Build Coastguard Worker      configuration if provided.
177*105f6285SAndroid Build Coastguard Worker    """
178*105f6285SAndroid Build Coastguard Worker    if base_config is None:
179*105f6285SAndroid Build Coastguard Worker      # Build a base_config with required elements from the new config_elem
180*105f6285SAndroid Build Coastguard Worker      name = config_elem.get('name')
181*105f6285SAndroid Build Coastguard Worker      base_config = cls(
182*105f6285SAndroid Build Coastguard Worker          name=name, android_target=config_elem.get('android_target', name))
183*105f6285SAndroid Build Coastguard Worker
184*105f6285SAndroid Build Coastguard Worker    return cls(
185*105f6285SAndroid Build Coastguard Worker        android_target=config_elem.get('android_target',
186*105f6285SAndroid Build Coastguard Worker                                       base_config.android_target),
187*105f6285SAndroid Build Coastguard Worker        name=config_elem.get('name', base_config.name),
188*105f6285SAndroid Build Coastguard Worker        allowed_projects_file=config_elem.get(
189*105f6285SAndroid Build Coastguard Worker            'allowed_projects_file', base_config.allowed_projects_file),
190*105f6285SAndroid Build Coastguard Worker        build_goals=_get_build_config_goals(config_elem,
191*105f6285SAndroid Build Coastguard Worker                                            base_config.build_goals),
192*105f6285SAndroid Build Coastguard Worker        build_flags=_get_build_config_flags(config_elem,
193*105f6285SAndroid Build Coastguard Worker                                            base_config.build_flags),
194*105f6285SAndroid Build Coastguard Worker        tags=_get_config_tags(config_elem, base_config.tags),
195*105f6285SAndroid Build Coastguard Worker        overlays=_get_overlays(config_elem, base_config.overlays),
196*105f6285SAndroid Build Coastguard Worker        allow_readwrite=_get_allow_readwrite(config_elem,
197*105f6285SAndroid Build Coastguard Worker                                             base_config.allow_readwrite),
198*105f6285SAndroid Build Coastguard Worker        views=_get_views(config_elem, fs_view_map, base_config.views),
199*105f6285SAndroid Build Coastguard Worker        allow_readwrite_all=_get_allowed_readwrite_all(
200*105f6285SAndroid Build Coastguard Worker            config_elem, base_config.allow_readwrite_all),
201*105f6285SAndroid Build Coastguard Worker        configurations=_get_configurations(config_elem,
202*105f6285SAndroid Build Coastguard Worker                                           base_config.configurations))
203*105f6285SAndroid Build Coastguard Worker
204*105f6285SAndroid Build Coastguard Worker
205*105f6285SAndroid Build Coastguard Workerdef _get_configurations(config_elem, base):
206*105f6285SAndroid Build Coastguard Worker  configs = dict(base)
207*105f6285SAndroid Build Coastguard Worker  configs.update({
208*105f6285SAndroid Build Coastguard Worker      config.get('name'): config.get('value')
209*105f6285SAndroid Build Coastguard Worker      for config in config_elem.findall('config')
210*105f6285SAndroid Build Coastguard Worker  })
211*105f6285SAndroid Build Coastguard Worker  return configs
212*105f6285SAndroid Build Coastguard Worker
213*105f6285SAndroid Build Coastguard Worker
214*105f6285SAndroid Build Coastguard Workerdef _get_build_config_goals(config_elem, base=None):
215*105f6285SAndroid Build Coastguard Worker  """Retrieves goals from build_config or target.
216*105f6285SAndroid Build Coastguard Worker
217*105f6285SAndroid Build Coastguard Worker  Args:
218*105f6285SAndroid Build Coastguard Worker    config_elem: A build_config or target xml element.
219*105f6285SAndroid Build Coastguard Worker    base: Initial list of goals to prepend to the list
220*105f6285SAndroid Build Coastguard Worker
221*105f6285SAndroid Build Coastguard Worker  Returns:
222*105f6285SAndroid Build Coastguard Worker    A list of tuples where the first element of the tuple is the build goal
223*105f6285SAndroid Build Coastguard Worker    name, and the second is a list of the contexts to which this goal applies.
224*105f6285SAndroid Build Coastguard Worker  """
225*105f6285SAndroid Build Coastguard Worker
226*105f6285SAndroid Build Coastguard Worker  return base + [(goal.get('name'), set(goal.get('contexts').split(','))
227*105f6285SAndroid Build Coastguard Worker                  if goal.get('contexts') else None)
228*105f6285SAndroid Build Coastguard Worker                 for goal in config_elem.findall('goal')]
229*105f6285SAndroid Build Coastguard Worker
230*105f6285SAndroid Build Coastguard Worker
231*105f6285SAndroid Build Coastguard Workerdef _get_build_config_flags(config_elem, base=None):
232*105f6285SAndroid Build Coastguard Worker  """See _get_build_config_goals. Gets 'flag' instead of 'goal'."""
233*105f6285SAndroid Build Coastguard Worker  return base + [(goal.get('name'), set(goal.get('contexts').split(','))
234*105f6285SAndroid Build Coastguard Worker                  if goal.get('contexts') else None)
235*105f6285SAndroid Build Coastguard Worker                 for goal in config_elem.findall('flag')]
236*105f6285SAndroid Build Coastguard Worker
237*105f6285SAndroid Build Coastguard Worker
238*105f6285SAndroid Build Coastguard Workerdef _get_config_tags(config_elem, base=frozenset()):
239*105f6285SAndroid Build Coastguard Worker  """Retrieves tags from build_config or target.
240*105f6285SAndroid Build Coastguard Worker
241*105f6285SAndroid Build Coastguard Worker  Args:
242*105f6285SAndroid Build Coastguard Worker    config_elem: A build_config or target xml element.
243*105f6285SAndroid Build Coastguard Worker    base: Initial list of tags to seed the set
244*105f6285SAndroid Build Coastguard Worker
245*105f6285SAndroid Build Coastguard Worker  Returns:
246*105f6285SAndroid Build Coastguard Worker    A set of tags for a build_config.
247*105f6285SAndroid Build Coastguard Worker  """
248*105f6285SAndroid Build Coastguard Worker  tags = config_elem.get('tags')
249*105f6285SAndroid Build Coastguard Worker  return base.union(set(tags.split(',')) if tags else set())
250*105f6285SAndroid Build Coastguard Worker
251*105f6285SAndroid Build Coastguard Worker
252*105f6285SAndroid Build Coastguard Workerdef _get_allowed_readwrite_all(config_elem, default=False):
253*105f6285SAndroid Build Coastguard Worker  """Determines if build_config or target is set to allow readwrite for all source paths.
254*105f6285SAndroid Build Coastguard Worker
255*105f6285SAndroid Build Coastguard Worker  Args:
256*105f6285SAndroid Build Coastguard Worker    config_elem: A build_config or target xml element.
257*105f6285SAndroid Build Coastguard Worker    default: Value to use if element doesn't contain the allow_readwrite_all
258*105f6285SAndroid Build Coastguard Worker      attribute.
259*105f6285SAndroid Build Coastguard Worker
260*105f6285SAndroid Build Coastguard Worker  Returns:
261*105f6285SAndroid Build Coastguard Worker    True if build config is set to allow readwrite for all sorce paths
262*105f6285SAndroid Build Coastguard Worker  """
263*105f6285SAndroid Build Coastguard Worker  value = config_elem.get('allow_readwrite_all')
264*105f6285SAndroid Build Coastguard Worker  return value == 'true' if value else default
265*105f6285SAndroid Build Coastguard Worker
266*105f6285SAndroid Build Coastguard Worker
267*105f6285SAndroid Build Coastguard Workerdef _get_overlays(config_elem, base=None):
268*105f6285SAndroid Build Coastguard Worker  """Retrieves list of overlays from build_config or target.
269*105f6285SAndroid Build Coastguard Worker
270*105f6285SAndroid Build Coastguard Worker  Args:
271*105f6285SAndroid Build Coastguard Worker    config_elem: A build_config or target xml element.
272*105f6285SAndroid Build Coastguard Worker    base: Initial list of overlays to prepend to the list
273*105f6285SAndroid Build Coastguard Worker
274*105f6285SAndroid Build Coastguard Worker  Returns:
275*105f6285SAndroid Build Coastguard Worker    A list of tuples of overlays and replacement paths to mount for a
276*105f6285SAndroid Build Coastguard Worker    build_config or target.
277*105f6285SAndroid Build Coastguard Worker  """
278*105f6285SAndroid Build Coastguard Worker  overlays = []
279*105f6285SAndroid Build Coastguard Worker  for overlay in config_elem.findall('overlay'):
280*105f6285SAndroid Build Coastguard Worker    overlays.append(
281*105f6285SAndroid Build Coastguard Worker        Overlay(
282*105f6285SAndroid Build Coastguard Worker            name=overlay.get('name'),
283*105f6285SAndroid Build Coastguard Worker            replacement_paths=set([
284*105f6285SAndroid Build Coastguard Worker                path.get('path') for path in overlay.findall('replacement_path')
285*105f6285SAndroid Build Coastguard Worker            ])))
286*105f6285SAndroid Build Coastguard Worker  return base + overlays
287*105f6285SAndroid Build Coastguard Worker
288*105f6285SAndroid Build Coastguard Worker
289*105f6285SAndroid Build Coastguard Workerdef _get_views(config_elem, fs_view_map, base=None):
290*105f6285SAndroid Build Coastguard Worker  """Retrieves list of views from build_config or target.
291*105f6285SAndroid Build Coastguard Worker
292*105f6285SAndroid Build Coastguard Worker  Args:
293*105f6285SAndroid Build Coastguard Worker    config_elem: A build_config or target xml element.
294*105f6285SAndroid Build Coastguard Worker    base: Initial list of views to prepend to the list
295*105f6285SAndroid Build Coastguard Worker
296*105f6285SAndroid Build Coastguard Worker  Returns:
297*105f6285SAndroid Build Coastguard Worker    A list of (source, destination) string path tuple to be mounted. See view
298*105f6285SAndroid Build Coastguard Worker      nodes in XML.
299*105f6285SAndroid Build Coastguard Worker  """
300*105f6285SAndroid Build Coastguard Worker  return base + [
301*105f6285SAndroid Build Coastguard Worker      fs for o in config_elem.findall('view')
302*105f6285SAndroid Build Coastguard Worker      for fs in fs_view_map[o.get('name')]
303*105f6285SAndroid Build Coastguard Worker  ]
304*105f6285SAndroid Build Coastguard Worker
305*105f6285SAndroid Build Coastguard Worker
306*105f6285SAndroid Build Coastguard Workerdef _get_allow_readwrite(config_elem, base=None):
307*105f6285SAndroid Build Coastguard Worker  """Retrieves list of directories to be mounted rw from build_config or target.
308*105f6285SAndroid Build Coastguard Worker
309*105f6285SAndroid Build Coastguard Worker  Args:
310*105f6285SAndroid Build Coastguard Worker    config_elem: A build_config or target xml element.
311*105f6285SAndroid Build Coastguard Worker    base: Initial list of rw directories to prepend to the list
312*105f6285SAndroid Build Coastguard Worker
313*105f6285SAndroid Build Coastguard Worker  Returns:
314*105f6285SAndroid Build Coastguard Worker    A list of directories to be mounted rw.
315*105f6285SAndroid Build Coastguard Worker  """
316*105f6285SAndroid Build Coastguard Worker  return (base +
317*105f6285SAndroid Build Coastguard Worker          [o.get('path') for o in config_elem.findall('allow_readwrite')])
318*105f6285SAndroid Build Coastguard Worker
319*105f6285SAndroid Build Coastguard Worker
320*105f6285SAndroid Build Coastguard Workerdef _get_fs_view_map(config):
321*105f6285SAndroid Build Coastguard Worker  """Retrieves the map of filesystem views.
322*105f6285SAndroid Build Coastguard Worker
323*105f6285SAndroid Build Coastguard Worker  Args:
324*105f6285SAndroid Build Coastguard Worker    config: An XML Element that is the root of the config XML tree.
325*105f6285SAndroid Build Coastguard Worker
326*105f6285SAndroid Build Coastguard Worker  Returns:
327*105f6285SAndroid Build Coastguard Worker    A dict of filesystem views keyed by view name. A filesystem view is a
328*105f6285SAndroid Build Coastguard Worker    list of (source, destination) string path tuples.
329*105f6285SAndroid Build Coastguard Worker  """
330*105f6285SAndroid Build Coastguard Worker  # A valid config file is not required to include FS Views, only overlay
331*105f6285SAndroid Build Coastguard Worker  # targets.
332*105f6285SAndroid Build Coastguard Worker  return {
333*105f6285SAndroid Build Coastguard Worker      view.get('name'): [(path.get('source'), path.get('destination'))
334*105f6285SAndroid Build Coastguard Worker                         for path in view.findall('path')
335*105f6285SAndroid Build Coastguard Worker                        ] for view in config.findall('view')
336*105f6285SAndroid Build Coastguard Worker  }
337*105f6285SAndroid Build Coastguard Worker
338*105f6285SAndroid Build Coastguard Worker
339*105f6285SAndroid Build Coastguard Workerdef _get_build_config_map(config):
340*105f6285SAndroid Build Coastguard Worker  """Retrieves a map of all build config.
341*105f6285SAndroid Build Coastguard Worker
342*105f6285SAndroid Build Coastguard Worker  Args:
343*105f6285SAndroid Build Coastguard Worker    config: An XML Element that is the root of the config XML tree.
344*105f6285SAndroid Build Coastguard Worker
345*105f6285SAndroid Build Coastguard Worker  Returns:
346*105f6285SAndroid Build Coastguard Worker    A dict of BuildConfig keyed by build_target.
347*105f6285SAndroid Build Coastguard Worker  """
348*105f6285SAndroid Build Coastguard Worker  fs_view_map = _get_fs_view_map(config)
349*105f6285SAndroid Build Coastguard Worker  build_config_map = {}
350*105f6285SAndroid Build Coastguard Worker  for target_config in config.findall('target'):
351*105f6285SAndroid Build Coastguard Worker    base_target = BuildConfig.from_config(target_config, fs_view_map)
352*105f6285SAndroid Build Coastguard Worker
353*105f6285SAndroid Build Coastguard Worker    for build_config in target_config.findall('build_config'):
354*105f6285SAndroid Build Coastguard Worker      build_target = BuildConfig.from_config(build_config, fs_view_map,
355*105f6285SAndroid Build Coastguard Worker                                             base_target)
356*105f6285SAndroid Build Coastguard Worker      build_target.validate()
357*105f6285SAndroid Build Coastguard Worker      build_config_map[build_target.name] = build_target
358*105f6285SAndroid Build Coastguard Worker
359*105f6285SAndroid Build Coastguard Worker  return build_config_map
360*105f6285SAndroid Build Coastguard Worker
361*105f6285SAndroid Build Coastguard Worker
362*105f6285SAndroid Build Coastguard Workerclass Config:
363*105f6285SAndroid Build Coastguard Worker  """Presents an API to the static XML configuration."""
364*105f6285SAndroid Build Coastguard Worker
365*105f6285SAndroid Build Coastguard Worker  def __init__(self, config_filename):
366*105f6285SAndroid Build Coastguard Worker    """Initializes a Config instance from the specificed filename
367*105f6285SAndroid Build Coastguard Worker
368*105f6285SAndroid Build Coastguard Worker    This method parses the XML content of the file named by config_filename
369*105f6285SAndroid Build Coastguard Worker    into internal data structures. You can then use various methods to query
370*105f6285SAndroid Build Coastguard Worker    the static config.
371*105f6285SAndroid Build Coastguard Worker
372*105f6285SAndroid Build Coastguard Worker    Args:
373*105f6285SAndroid Build Coastguard Worker      config_filename: The name of the file from which to load the config.
374*105f6285SAndroid Build Coastguard Worker    """
375*105f6285SAndroid Build Coastguard Worker
376*105f6285SAndroid Build Coastguard Worker    tree = ET.parse(config_filename)
377*105f6285SAndroid Build Coastguard Worker    config = tree.getroot()
378*105f6285SAndroid Build Coastguard Worker    self._build_config_map = _get_build_config_map(config)
379*105f6285SAndroid Build Coastguard Worker
380*105f6285SAndroid Build Coastguard Worker  def get_available_build_targets(self):
381*105f6285SAndroid Build Coastguard Worker    """Return a list of available build targets."""
382*105f6285SAndroid Build Coastguard Worker    return sorted(self._build_config_map.keys())
383*105f6285SAndroid Build Coastguard Worker
384*105f6285SAndroid Build Coastguard Worker  def get_tags(self, build_target):
385*105f6285SAndroid Build Coastguard Worker    """Given a build_target, return the (possibly empty) set of tags."""
386*105f6285SAndroid Build Coastguard Worker    return self._build_config_map[build_target].tags
387*105f6285SAndroid Build Coastguard Worker
388*105f6285SAndroid Build Coastguard Worker  def has_tag(self, build_target, tag):
389*105f6285SAndroid Build Coastguard Worker    """Return true if build_target has tag.
390*105f6285SAndroid Build Coastguard Worker
391*105f6285SAndroid Build Coastguard Worker    Args:
392*105f6285SAndroid Build Coastguard Worker      build_target: A string build_target to be queried.
393*105f6285SAndroid Build Coastguard Worker      tag: A string tag that this target may have.
394*105f6285SAndroid Build Coastguard Worker
395*105f6285SAndroid Build Coastguard Worker    Returns:
396*105f6285SAndroid Build Coastguard Worker      If the build_target has the tag, True. Otherwise, False.
397*105f6285SAndroid Build Coastguard Worker    """
398*105f6285SAndroid Build Coastguard Worker    return tag in self._build_config_map[build_target].tags
399*105f6285SAndroid Build Coastguard Worker
400*105f6285SAndroid Build Coastguard Worker  def get_allowed_projects_file(self, build_target):
401*105f6285SAndroid Build Coastguard Worker    """Given a build_target, return a string with the allowed projects file."""
402*105f6285SAndroid Build Coastguard Worker    return self._build_config_map[build_target].allowed_projects_file
403*105f6285SAndroid Build Coastguard Worker
404*105f6285SAndroid Build Coastguard Worker  def get_build_config_android_target(self, build_target):
405*105f6285SAndroid Build Coastguard Worker    """Given a build_target, return an android_target.
406*105f6285SAndroid Build Coastguard Worker
407*105f6285SAndroid Build Coastguard Worker    Generally a build_target maps directory to the android_target of the same
408*105f6285SAndroid Build Coastguard Worker    name, but they can differ. In a config.xml file, the name attribute of a
409*105f6285SAndroid Build Coastguard Worker    target element is the android_target (which is used for lunch). The name
410*105f6285SAndroid Build Coastguard Worker    attribute (if any) of a build_config element is the build_target. If a
411*105f6285SAndroid Build Coastguard Worker    build_config element does not have a name attribute, then the build_target
412*105f6285SAndroid Build Coastguard Worker    is the android_target.
413*105f6285SAndroid Build Coastguard Worker
414*105f6285SAndroid Build Coastguard Worker    Args:
415*105f6285SAndroid Build Coastguard Worker      build_target: A string build_target to be queried.
416*105f6285SAndroid Build Coastguard Worker
417*105f6285SAndroid Build Coastguard Worker    Returns:
418*105f6285SAndroid Build Coastguard Worker      A string android_target that can be used for lunch.
419*105f6285SAndroid Build Coastguard Worker    """
420*105f6285SAndroid Build Coastguard Worker    return self._build_config_map[build_target].android_target
421*105f6285SAndroid Build Coastguard Worker
422*105f6285SAndroid Build Coastguard Worker  def get_build_goals(self, build_target, contexts=frozenset()):
423*105f6285SAndroid Build Coastguard Worker    """Given a build_target and a context, return a list of build goals.
424*105f6285SAndroid Build Coastguard Worker
425*105f6285SAndroid Build Coastguard Worker    For a given build_target, we may build in a variety of contexts. For
426*105f6285SAndroid Build Coastguard Worker    example we might build in continuous integration, or we might build
427*105f6285SAndroid Build Coastguard Worker    locally, or other contexts defined by the configuration file and scripts
428*105f6285SAndroid Build Coastguard Worker    that use it. The contexts parameter is a set of strings that specify the
429*105f6285SAndroid Build Coastguard Worker    contexts for which this function should retrieve goals.
430*105f6285SAndroid Build Coastguard Worker
431*105f6285SAndroid Build Coastguard Worker    In the configuration file, each goal has a contexts attribute, which
432*105f6285SAndroid Build Coastguard Worker    specifies the contexts to which the goal applies. We treat a goal with no
433*105f6285SAndroid Build Coastguard Worker    contexts attribute as applying to all contexts.
434*105f6285SAndroid Build Coastguard Worker
435*105f6285SAndroid Build Coastguard Worker    Example:
436*105f6285SAndroid Build Coastguard Worker
437*105f6285SAndroid Build Coastguard Worker      <build_config>
438*105f6285SAndroid Build Coastguard Worker        <goal name="droid"/>
439*105f6285SAndroid Build Coastguard Worker        <goal name="dist" contexts="ota"/>
440*105f6285SAndroid Build Coastguard Worker      </build_config>
441*105f6285SAndroid Build Coastguard Worker
442*105f6285SAndroid Build Coastguard Worker      Here we have the goal "droid", which matches all contexts, and the goal
443*105f6285SAndroid Build Coastguard Worker      "dist", which matches the "ota" context. Invoking this method with the
444*105f6285SAndroid Build Coastguard Worker      set(['ota']) would return ['droid', 'dist'].
445*105f6285SAndroid Build Coastguard Worker
446*105f6285SAndroid Build Coastguard Worker    Args:
447*105f6285SAndroid Build Coastguard Worker      build_target: A string build_target to be queried.
448*105f6285SAndroid Build Coastguard Worker      context: A set of contexts for which to retrieve goals.
449*105f6285SAndroid Build Coastguard Worker
450*105f6285SAndroid Build Coastguard Worker    Returns:
451*105f6285SAndroid Build Coastguard Worker      A list of strings, where each string is a goal to be passed to make.
452*105f6285SAndroid Build Coastguard Worker    """
453*105f6285SAndroid Build Coastguard Worker
454*105f6285SAndroid Build Coastguard Worker    build_goals = []
455*105f6285SAndroid Build Coastguard Worker    for goal, build_contexts in self._build_config_map[
456*105f6285SAndroid Build Coastguard Worker        build_target].build_goals:
457*105f6285SAndroid Build Coastguard Worker      if not build_contexts:
458*105f6285SAndroid Build Coastguard Worker        build_goals.append(goal)
459*105f6285SAndroid Build Coastguard Worker      elif build_contexts.intersection(contexts):
460*105f6285SAndroid Build Coastguard Worker        build_goals.append(goal)
461*105f6285SAndroid Build Coastguard Worker
462*105f6285SAndroid Build Coastguard Worker    return build_goals
463*105f6285SAndroid Build Coastguard Worker
464*105f6285SAndroid Build Coastguard Worker  def get_build_flags(self, build_target, contexts=frozenset()):
465*105f6285SAndroid Build Coastguard Worker    """See get_build_goals. Gets flags instead of goals."""
466*105f6285SAndroid Build Coastguard Worker    build_flags = []
467*105f6285SAndroid Build Coastguard Worker    for flag, build_contexts in self._build_config_map[
468*105f6285SAndroid Build Coastguard Worker        build_target].build_flags:
469*105f6285SAndroid Build Coastguard Worker      if not build_contexts:
470*105f6285SAndroid Build Coastguard Worker        build_flags.append(flag)
471*105f6285SAndroid Build Coastguard Worker      elif build_contexts.intersection(contexts):
472*105f6285SAndroid Build Coastguard Worker        build_flags.append(flag)
473*105f6285SAndroid Build Coastguard Worker
474*105f6285SAndroid Build Coastguard Worker    return build_flags
475*105f6285SAndroid Build Coastguard Worker
476*105f6285SAndroid Build Coastguard Worker  def get_rw_allowlist_map(self):
477*105f6285SAndroid Build Coastguard Worker    """Return read-write allowlist map.
478*105f6285SAndroid Build Coastguard Worker
479*105f6285SAndroid Build Coastguard Worker    Returns:
480*105f6285SAndroid Build Coastguard Worker      A dict of string lists of keyed by target name. Each value in the dict is
481*105f6285SAndroid Build Coastguard Worker      a list of allowed read-write paths corresponding to the target.
482*105f6285SAndroid Build Coastguard Worker    """
483*105f6285SAndroid Build Coastguard Worker    return {b.name: b.allow_readwrite for b in self._build_config_map.values()}
484*105f6285SAndroid Build Coastguard Worker
485*105f6285SAndroid Build Coastguard Worker  def get_allow_readwrite_all(self, build_target):
486*105f6285SAndroid Build Coastguard Worker    """Return True if the target should mount all its source as read-write.
487*105f6285SAndroid Build Coastguard Worker
488*105f6285SAndroid Build Coastguard Worker    Args:
489*105f6285SAndroid Build Coastguard Worker      build_target: A string build_target to be queried.
490*105f6285SAndroid Build Coastguard Worker
491*105f6285SAndroid Build Coastguard Worker    Returns:
492*105f6285SAndroid Build Coastguard Worker      True if the target should mount all its source as read-write.
493*105f6285SAndroid Build Coastguard Worker    """
494*105f6285SAndroid Build Coastguard Worker    return self._build_config_map[build_target].allow_readwrite_all
495*105f6285SAndroid Build Coastguard Worker
496*105f6285SAndroid Build Coastguard Worker  def get_overlay_map(self):
497*105f6285SAndroid Build Coastguard Worker    """Return the overlay map.
498*105f6285SAndroid Build Coastguard Worker
499*105f6285SAndroid Build Coastguard Worker    Returns:
500*105f6285SAndroid Build Coastguard Worker      A dict of keyed by target name. Each value in the dict is a list of
501*105f6285SAndroid Build Coastguard Worker      overlay names corresponding to the target.
502*105f6285SAndroid Build Coastguard Worker    """
503*105f6285SAndroid Build Coastguard Worker    return {
504*105f6285SAndroid Build Coastguard Worker        b.name: [o.name for o in b.overlays
505*105f6285SAndroid Build Coastguard Worker                ] for b in self._build_config_map.values()
506*105f6285SAndroid Build Coastguard Worker    }
507*105f6285SAndroid Build Coastguard Worker
508*105f6285SAndroid Build Coastguard Worker  def get_fs_view_map(self):
509*105f6285SAndroid Build Coastguard Worker    """Return the filesystem view map.
510*105f6285SAndroid Build Coastguard Worker
511*105f6285SAndroid Build Coastguard Worker    Returns:
512*105f6285SAndroid Build Coastguard Worker      A dict of filesystem views keyed by target name. A filesystem view is a
513*105f6285SAndroid Build Coastguard Worker      list of (source, destination) string path tuples.
514*105f6285SAndroid Build Coastguard Worker    """
515*105f6285SAndroid Build Coastguard Worker    return {b.name: b.views for b in self._build_config_map.values()}
516*105f6285SAndroid Build Coastguard Worker
517*105f6285SAndroid Build Coastguard Worker  def get_build_config(self, build_target):
518*105f6285SAndroid Build Coastguard Worker    return self._build_config_map[build_target]
519*105f6285SAndroid Build Coastguard Worker
520*105f6285SAndroid Build Coastguard Worker
521*105f6285SAndroid Build Coastguard Workerdef factory(config_filename):
522*105f6285SAndroid Build Coastguard Worker  """Create an instance of a Config class.
523*105f6285SAndroid Build Coastguard Worker
524*105f6285SAndroid Build Coastguard Worker  Args:
525*105f6285SAndroid Build Coastguard Worker    config_filename: The name of the file from which to load the config. This
526*105f6285SAndroid Build Coastguard Worker      can be None, which results in this function returning None.
527*105f6285SAndroid Build Coastguard Worker
528*105f6285SAndroid Build Coastguard Worker  Returns:
529*105f6285SAndroid Build Coastguard Worker    If config_filename is None, returns None. Otherwise, a new instance of a
530*105f6285SAndroid Build Coastguard Worker    Config class containing the configuration parsed from config_filename.
531*105f6285SAndroid Build Coastguard Worker  """
532*105f6285SAndroid Build Coastguard Worker  if config_filename is None:
533*105f6285SAndroid Build Coastguard Worker    return None
534*105f6285SAndroid Build Coastguard Worker
535*105f6285SAndroid Build Coastguard Worker  return Config(config_filename)
536