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