1*b9df5ad1SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*b9df5ad1SAndroid Build Coastguard Worker 3*b9df5ad1SAndroid Build Coastguard Worker# 4*b9df5ad1SAndroid Build Coastguard Worker# Copyright (C) 2012 The Android Open Source Project 5*b9df5ad1SAndroid Build Coastguard Worker# 6*b9df5ad1SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 7*b9df5ad1SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 8*b9df5ad1SAndroid Build Coastguard Worker# You may obtain a copy of the License at 9*b9df5ad1SAndroid Build Coastguard Worker# 10*b9df5ad1SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 11*b9df5ad1SAndroid Build Coastguard Worker# 12*b9df5ad1SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 13*b9df5ad1SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 14*b9df5ad1SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15*b9df5ad1SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 16*b9df5ad1SAndroid Build Coastguard Worker# limitations under the License. 17*b9df5ad1SAndroid Build Coastguard Worker# 18*b9df5ad1SAndroid Build Coastguard Worker 19*b9df5ad1SAndroid Build Coastguard Worker""" 20*b9df5ad1SAndroid Build Coastguard WorkerA parser for metadata_definitions.xml can also render the resulting model 21*b9df5ad1SAndroid Build Coastguard Workerover a Mako template. 22*b9df5ad1SAndroid Build Coastguard Worker 23*b9df5ad1SAndroid Build Coastguard WorkerUsage: 24*b9df5ad1SAndroid Build Coastguard Worker metadata_parser_xml.py <filename.xml> <template.mako> [<output_file>] 25*b9df5ad1SAndroid Build Coastguard Worker - outputs the resulting template to output_file (stdout if none specified) 26*b9df5ad1SAndroid Build Coastguard Worker 27*b9df5ad1SAndroid Build Coastguard WorkerModule: 28*b9df5ad1SAndroid Build Coastguard Worker The parser is also available as a module import (MetadataParserXml) to use 29*b9df5ad1SAndroid Build Coastguard Worker in other modules. 30*b9df5ad1SAndroid Build Coastguard Worker 31*b9df5ad1SAndroid Build Coastguard WorkerDependencies: 32*b9df5ad1SAndroid Build Coastguard Worker BeautifulSoup - an HTML/XML parser available to download from 33*b9df5ad1SAndroid Build Coastguard Worker http://www.crummy.com/software/BeautifulSoup/ 34*b9df5ad1SAndroid Build Coastguard Worker Mako - a template engine for Python, available to download from 35*b9df5ad1SAndroid Build Coastguard Worker http://www.makotemplates.org/ 36*b9df5ad1SAndroid Build Coastguard Worker""" 37*b9df5ad1SAndroid Build Coastguard Worker 38*b9df5ad1SAndroid Build Coastguard Workerimport sys 39*b9df5ad1SAndroid Build Coastguard Workerimport os 40*b9df5ad1SAndroid Build Coastguard Worker 41*b9df5ad1SAndroid Build Coastguard Workerfrom bs4 import BeautifulSoup 42*b9df5ad1SAndroid Build Coastguard Workerfrom bs4 import NavigableString 43*b9df5ad1SAndroid Build Coastguard Worker 44*b9df5ad1SAndroid Build Coastguard Workerfrom datetime import datetime 45*b9df5ad1SAndroid Build Coastguard Worker 46*b9df5ad1SAndroid Build Coastguard Workerfrom io import StringIO 47*b9df5ad1SAndroid Build Coastguard Worker 48*b9df5ad1SAndroid Build Coastguard Workerfrom mako.template import Template 49*b9df5ad1SAndroid Build Coastguard Workerfrom mako.lookup import TemplateLookup 50*b9df5ad1SAndroid Build Coastguard Workerfrom mako.runtime import Context 51*b9df5ad1SAndroid Build Coastguard Worker 52*b9df5ad1SAndroid Build Coastguard Workerfrom metadata_model import * 53*b9df5ad1SAndroid Build Coastguard Workerimport metadata_model 54*b9df5ad1SAndroid Build Coastguard Workerfrom metadata_validate import * 55*b9df5ad1SAndroid Build Coastguard Workerimport metadata_helpers 56*b9df5ad1SAndroid Build Coastguard Worker 57*b9df5ad1SAndroid Build Coastguard Workerclass MetadataParserXml: 58*b9df5ad1SAndroid Build Coastguard Worker """ 59*b9df5ad1SAndroid Build Coastguard Worker A class to parse any XML block that passes validation with metadata-validate. 60*b9df5ad1SAndroid Build Coastguard Worker It builds a metadata_model.Metadata graph and then renders it over a 61*b9df5ad1SAndroid Build Coastguard Worker Mako template. 62*b9df5ad1SAndroid Build Coastguard Worker 63*b9df5ad1SAndroid Build Coastguard Worker Attributes (Read-Only): 64*b9df5ad1SAndroid Build Coastguard Worker soup: an instance of BeautifulSoup corresponding to the XML contents 65*b9df5ad1SAndroid Build Coastguard Worker metadata: a constructed instance of metadata_model.Metadata 66*b9df5ad1SAndroid Build Coastguard Worker """ 67*b9df5ad1SAndroid Build Coastguard Worker def __init__(self, xml, file_name): 68*b9df5ad1SAndroid Build Coastguard Worker """ 69*b9df5ad1SAndroid Build Coastguard Worker Construct a new MetadataParserXml, immediately try to parse it into a 70*b9df5ad1SAndroid Build Coastguard Worker metadata model. 71*b9df5ad1SAndroid Build Coastguard Worker 72*b9df5ad1SAndroid Build Coastguard Worker Args: 73*b9df5ad1SAndroid Build Coastguard Worker xml: The XML block to use for the metadata 74*b9df5ad1SAndroid Build Coastguard Worker file_name: Source of the XML block, only for debugging/errors 75*b9df5ad1SAndroid Build Coastguard Worker 76*b9df5ad1SAndroid Build Coastguard Worker Raises: 77*b9df5ad1SAndroid Build Coastguard Worker ValueError: if the XML block failed to pass metadata_validate.py 78*b9df5ad1SAndroid Build Coastguard Worker """ 79*b9df5ad1SAndroid Build Coastguard Worker self._soup = validate_xml(xml) 80*b9df5ad1SAndroid Build Coastguard Worker 81*b9df5ad1SAndroid Build Coastguard Worker if self._soup is None: 82*b9df5ad1SAndroid Build Coastguard Worker raise ValueError("%s has an invalid XML file" % (file_name)) 83*b9df5ad1SAndroid Build Coastguard Worker 84*b9df5ad1SAndroid Build Coastguard Worker self._metadata = Metadata() 85*b9df5ad1SAndroid Build Coastguard Worker self._parse() 86*b9df5ad1SAndroid Build Coastguard Worker self._metadata.construct_graph() 87*b9df5ad1SAndroid Build Coastguard Worker 88*b9df5ad1SAndroid Build Coastguard Worker @staticmethod 89*b9df5ad1SAndroid Build Coastguard Worker def create_from_file(file_name): 90*b9df5ad1SAndroid Build Coastguard Worker """ 91*b9df5ad1SAndroid Build Coastguard Worker Construct a new MetadataParserXml by loading and parsing an XML file. 92*b9df5ad1SAndroid Build Coastguard Worker 93*b9df5ad1SAndroid Build Coastguard Worker Args: 94*b9df5ad1SAndroid Build Coastguard Worker file_name: Name of the XML file to load and parse. 95*b9df5ad1SAndroid Build Coastguard Worker 96*b9df5ad1SAndroid Build Coastguard Worker Raises: 97*b9df5ad1SAndroid Build Coastguard Worker ValueError: if the XML file failed to pass metadata_validate.py 98*b9df5ad1SAndroid Build Coastguard Worker 99*b9df5ad1SAndroid Build Coastguard Worker Returns: 100*b9df5ad1SAndroid Build Coastguard Worker MetadataParserXml instance representing the XML file. 101*b9df5ad1SAndroid Build Coastguard Worker """ 102*b9df5ad1SAndroid Build Coastguard Worker return MetadataParserXml(open(file_name).read(), file_name) 103*b9df5ad1SAndroid Build Coastguard Worker 104*b9df5ad1SAndroid Build Coastguard Worker @property 105*b9df5ad1SAndroid Build Coastguard Worker def soup(self): 106*b9df5ad1SAndroid Build Coastguard Worker return self._soup 107*b9df5ad1SAndroid Build Coastguard Worker 108*b9df5ad1SAndroid Build Coastguard Worker @property 109*b9df5ad1SAndroid Build Coastguard Worker def metadata(self): 110*b9df5ad1SAndroid Build Coastguard Worker return self._metadata 111*b9df5ad1SAndroid Build Coastguard Worker 112*b9df5ad1SAndroid Build Coastguard Worker @staticmethod 113*b9df5ad1SAndroid Build Coastguard Worker def _find_direct_strings(element): 114*b9df5ad1SAndroid Build Coastguard Worker if element.string is not None: 115*b9df5ad1SAndroid Build Coastguard Worker return [element.string] 116*b9df5ad1SAndroid Build Coastguard Worker 117*b9df5ad1SAndroid Build Coastguard Worker return [i for i in element.contents if isinstance(i, NavigableString)] 118*b9df5ad1SAndroid Build Coastguard Worker 119*b9df5ad1SAndroid Build Coastguard Worker @staticmethod 120*b9df5ad1SAndroid Build Coastguard Worker def _strings_no_nl(element): 121*b9df5ad1SAndroid Build Coastguard Worker return "".join([i.strip() for i in MetadataParserXml._find_direct_strings(element)]) 122*b9df5ad1SAndroid Build Coastguard Worker 123*b9df5ad1SAndroid Build Coastguard Worker def _parse(self): 124*b9df5ad1SAndroid Build Coastguard Worker 125*b9df5ad1SAndroid Build Coastguard Worker tags = self.soup.tags 126*b9df5ad1SAndroid Build Coastguard Worker if tags is not None: 127*b9df5ad1SAndroid Build Coastguard Worker for tag in tags.find_all('tag'): 128*b9df5ad1SAndroid Build Coastguard Worker self.metadata.insert_tag(tag['id'], tag.string) 129*b9df5ad1SAndroid Build Coastguard Worker 130*b9df5ad1SAndroid Build Coastguard Worker types = self.soup.types 131*b9df5ad1SAndroid Build Coastguard Worker if types is not None: 132*b9df5ad1SAndroid Build Coastguard Worker for tp in types.find_all('typedef'): 133*b9df5ad1SAndroid Build Coastguard Worker languages = {} 134*b9df5ad1SAndroid Build Coastguard Worker for lang in tp.find_all('language'): 135*b9df5ad1SAndroid Build Coastguard Worker languages[lang['name']] = lang.string 136*b9df5ad1SAndroid Build Coastguard Worker 137*b9df5ad1SAndroid Build Coastguard Worker self.metadata.insert_type(tp['name'], 'typedef', languages=languages) 138*b9df5ad1SAndroid Build Coastguard Worker 139*b9df5ad1SAndroid Build Coastguard Worker # add all entries, preserving the ordering of the XML file 140*b9df5ad1SAndroid Build Coastguard Worker # this is important for future ABI compatibility when generating code 141*b9df5ad1SAndroid Build Coastguard Worker entry_filter = lambda x: x.name == 'entry' or x.name == 'clone' 142*b9df5ad1SAndroid Build Coastguard Worker for entry in self.soup.find_all(entry_filter): 143*b9df5ad1SAndroid Build Coastguard Worker if entry.name == 'entry': 144*b9df5ad1SAndroid Build Coastguard Worker d = { 145*b9df5ad1SAndroid Build Coastguard Worker 'name': fully_qualified_name(entry), 146*b9df5ad1SAndroid Build Coastguard Worker 'type': entry['type'], 147*b9df5ad1SAndroid Build Coastguard Worker 'kind': find_kind(entry), 148*b9df5ad1SAndroid Build Coastguard Worker 'type_notes': entry.attrs.get('type_notes') 149*b9df5ad1SAndroid Build Coastguard Worker } 150*b9df5ad1SAndroid Build Coastguard Worker 151*b9df5ad1SAndroid Build Coastguard Worker d2 = self._parse_entry(entry) 152*b9df5ad1SAndroid Build Coastguard Worker insert = self.metadata.insert_entry 153*b9df5ad1SAndroid Build Coastguard Worker else: 154*b9df5ad1SAndroid Build Coastguard Worker d = { 155*b9df5ad1SAndroid Build Coastguard Worker 'name': entry['entry'], 156*b9df5ad1SAndroid Build Coastguard Worker 'kind': find_kind(entry), 157*b9df5ad1SAndroid Build Coastguard Worker 'target_kind': entry['kind'], 158*b9df5ad1SAndroid Build Coastguard Worker # no type since its the same 159*b9df5ad1SAndroid Build Coastguard Worker # no type_notes since its the same 160*b9df5ad1SAndroid Build Coastguard Worker } 161*b9df5ad1SAndroid Build Coastguard Worker d2 = {} 162*b9df5ad1SAndroid Build Coastguard Worker if 'hal_version' in entry.attrs: 163*b9df5ad1SAndroid Build Coastguard Worker d2['hal_version'] = entry['hal_version'] 164*b9df5ad1SAndroid Build Coastguard Worker 165*b9df5ad1SAndroid Build Coastguard Worker insert = self.metadata.insert_clone 166*b9df5ad1SAndroid Build Coastguard Worker 167*b9df5ad1SAndroid Build Coastguard Worker d3 = self._parse_entry_optional(entry) 168*b9df5ad1SAndroid Build Coastguard Worker 169*b9df5ad1SAndroid Build Coastguard Worker entry_dict = {**d, **d2, **d3} 170*b9df5ad1SAndroid Build Coastguard Worker insert(entry_dict) 171*b9df5ad1SAndroid Build Coastguard Worker 172*b9df5ad1SAndroid Build Coastguard Worker self.metadata.construct_graph() 173*b9df5ad1SAndroid Build Coastguard Worker 174*b9df5ad1SAndroid Build Coastguard Worker def _parse_entry(self, entry): 175*b9df5ad1SAndroid Build Coastguard Worker d = {} 176*b9df5ad1SAndroid Build Coastguard Worker 177*b9df5ad1SAndroid Build Coastguard Worker # 178*b9df5ad1SAndroid Build Coastguard Worker # Visibility 179*b9df5ad1SAndroid Build Coastguard Worker # 180*b9df5ad1SAndroid Build Coastguard Worker d['visibility'] = entry.get('visibility') 181*b9df5ad1SAndroid Build Coastguard Worker 182*b9df5ad1SAndroid Build Coastguard Worker # 183*b9df5ad1SAndroid Build Coastguard Worker # Synthetic ? 184*b9df5ad1SAndroid Build Coastguard Worker # 185*b9df5ad1SAndroid Build Coastguard Worker d['synthetic'] = entry.get('synthetic') == 'true' 186*b9df5ad1SAndroid Build Coastguard Worker 187*b9df5ad1SAndroid Build Coastguard Worker # 188*b9df5ad1SAndroid Build Coastguard Worker # Permission needed ? 189*b9df5ad1SAndroid Build Coastguard Worker # 190*b9df5ad1SAndroid Build Coastguard Worker d['permission_needed'] = entry.get('permission_needed') 191*b9df5ad1SAndroid Build Coastguard Worker 192*b9df5ad1SAndroid Build Coastguard Worker # Aconfig flag gating this entry ? 193*b9df5ad1SAndroid Build Coastguard Worker d['aconfig_flag'] = entry.get('aconfig_flag') 194*b9df5ad1SAndroid Build Coastguard Worker 195*b9df5ad1SAndroid Build Coastguard Worker # 196*b9df5ad1SAndroid Build Coastguard Worker # Hardware Level (one of limited, legacy, full) 197*b9df5ad1SAndroid Build Coastguard Worker # 198*b9df5ad1SAndroid Build Coastguard Worker d['hwlevel'] = entry.get('hwlevel') 199*b9df5ad1SAndroid Build Coastguard Worker 200*b9df5ad1SAndroid Build Coastguard Worker # 201*b9df5ad1SAndroid Build Coastguard Worker # Deprecated ? 202*b9df5ad1SAndroid Build Coastguard Worker # 203*b9df5ad1SAndroid Build Coastguard Worker d['deprecated'] = entry.get('deprecated') == 'true' 204*b9df5ad1SAndroid Build Coastguard Worker 205*b9df5ad1SAndroid Build Coastguard Worker # 206*b9df5ad1SAndroid Build Coastguard Worker # Optional for non-full hardware level devices 207*b9df5ad1SAndroid Build Coastguard Worker # 208*b9df5ad1SAndroid Build Coastguard Worker d['optional'] = entry.get('optional') == 'true' 209*b9df5ad1SAndroid Build Coastguard Worker 210*b9df5ad1SAndroid Build Coastguard Worker # 211*b9df5ad1SAndroid Build Coastguard Worker # Typedef 212*b9df5ad1SAndroid Build Coastguard Worker # 213*b9df5ad1SAndroid Build Coastguard Worker d['type_name'] = entry.get('typedef') 214*b9df5ad1SAndroid Build Coastguard Worker 215*b9df5ad1SAndroid Build Coastguard Worker # 216*b9df5ad1SAndroid Build Coastguard Worker # Initial HIDL HAL version the entry was added in 217*b9df5ad1SAndroid Build Coastguard Worker d['hal_version'] = entry.get('hal_version') 218*b9df5ad1SAndroid Build Coastguard Worker 219*b9df5ad1SAndroid Build Coastguard Worker # 220*b9df5ad1SAndroid Build Coastguard Worker # HAL version from which this entry became a session characteristic ? 221*b9df5ad1SAndroid Build Coastguard Worker d['session_characteristics_key_since'] = entry.get('session_characteristics_key_since') 222*b9df5ad1SAndroid Build Coastguard Worker 223*b9df5ad1SAndroid Build Coastguard Worker # 224*b9df5ad1SAndroid Build Coastguard Worker # Enum 225*b9df5ad1SAndroid Build Coastguard Worker # 226*b9df5ad1SAndroid Build Coastguard Worker if entry.get('enum', 'false') == 'true': 227*b9df5ad1SAndroid Build Coastguard Worker 228*b9df5ad1SAndroid Build Coastguard Worker enum_values = [] 229*b9df5ad1SAndroid Build Coastguard Worker enum_deprecateds = [] 230*b9df5ad1SAndroid Build Coastguard Worker enum_optionals = [] 231*b9df5ad1SAndroid Build Coastguard Worker enum_visibilities = {} 232*b9df5ad1SAndroid Build Coastguard Worker enum_notes = {} 233*b9df5ad1SAndroid Build Coastguard Worker enum_sdk_notes = {} 234*b9df5ad1SAndroid Build Coastguard Worker enum_ndk_notes = {} 235*b9df5ad1SAndroid Build Coastguard Worker enum_ids = {} 236*b9df5ad1SAndroid Build Coastguard Worker enum_hal_versions = {} 237*b9df5ad1SAndroid Build Coastguard Worker enum_aconfig_flags = {} 238*b9df5ad1SAndroid Build Coastguard Worker for value in entry.enum.find_all('value'): 239*b9df5ad1SAndroid Build Coastguard Worker 240*b9df5ad1SAndroid Build Coastguard Worker value_body = self._strings_no_nl(value) 241*b9df5ad1SAndroid Build Coastguard Worker enum_values.append(value_body) 242*b9df5ad1SAndroid Build Coastguard Worker 243*b9df5ad1SAndroid Build Coastguard Worker if value.attrs.get('deprecated', 'false') == 'true': 244*b9df5ad1SAndroid Build Coastguard Worker enum_deprecateds.append(value_body) 245*b9df5ad1SAndroid Build Coastguard Worker 246*b9df5ad1SAndroid Build Coastguard Worker if value.attrs.get('optional', 'false') == 'true': 247*b9df5ad1SAndroid Build Coastguard Worker enum_optionals.append(value_body) 248*b9df5ad1SAndroid Build Coastguard Worker 249*b9df5ad1SAndroid Build Coastguard Worker visibility = value.attrs.get('visibility') 250*b9df5ad1SAndroid Build Coastguard Worker if visibility is not None: 251*b9df5ad1SAndroid Build Coastguard Worker enum_visibilities[value_body] = visibility 252*b9df5ad1SAndroid Build Coastguard Worker 253*b9df5ad1SAndroid Build Coastguard Worker notes = value.find('notes') 254*b9df5ad1SAndroid Build Coastguard Worker if notes is not None: 255*b9df5ad1SAndroid Build Coastguard Worker enum_notes[value_body] = notes.string 256*b9df5ad1SAndroid Build Coastguard Worker 257*b9df5ad1SAndroid Build Coastguard Worker sdk_notes = value.find('sdk_notes') 258*b9df5ad1SAndroid Build Coastguard Worker if sdk_notes is not None: 259*b9df5ad1SAndroid Build Coastguard Worker enum_sdk_notes[value_body] = sdk_notes.string 260*b9df5ad1SAndroid Build Coastguard Worker 261*b9df5ad1SAndroid Build Coastguard Worker ndk_notes = value.find('ndk_notes') 262*b9df5ad1SAndroid Build Coastguard Worker if ndk_notes is not None: 263*b9df5ad1SAndroid Build Coastguard Worker enum_ndk_notes[value_body] = ndk_notes.string 264*b9df5ad1SAndroid Build Coastguard Worker 265*b9df5ad1SAndroid Build Coastguard Worker if value.attrs.get('id') is not None: 266*b9df5ad1SAndroid Build Coastguard Worker enum_ids[value_body] = value['id'] 267*b9df5ad1SAndroid Build Coastguard Worker 268*b9df5ad1SAndroid Build Coastguard Worker if value.attrs.get('hal_version') is not None: 269*b9df5ad1SAndroid Build Coastguard Worker enum_hal_versions[value_body] = value['hal_version'] 270*b9df5ad1SAndroid Build Coastguard Worker 271*b9df5ad1SAndroid Build Coastguard Worker if value.attrs.get('aconfig_flag') is not None: 272*b9df5ad1SAndroid Build Coastguard Worker enum_aconfig_flags[value_body] = value['aconfig_flag'] 273*b9df5ad1SAndroid Build Coastguard Worker 274*b9df5ad1SAndroid Build Coastguard Worker d['enum_values'] = enum_values 275*b9df5ad1SAndroid Build Coastguard Worker d['enum_deprecateds'] = enum_deprecateds 276*b9df5ad1SAndroid Build Coastguard Worker d['enum_optionals'] = enum_optionals 277*b9df5ad1SAndroid Build Coastguard Worker d['enum_visibilities'] = enum_visibilities 278*b9df5ad1SAndroid Build Coastguard Worker d['enum_notes'] = enum_notes 279*b9df5ad1SAndroid Build Coastguard Worker d['enum_sdk_notes'] = enum_sdk_notes 280*b9df5ad1SAndroid Build Coastguard Worker d['enum_ndk_notes'] = enum_ndk_notes 281*b9df5ad1SAndroid Build Coastguard Worker d['enum_ids'] = enum_ids 282*b9df5ad1SAndroid Build Coastguard Worker d['enum_hal_versions'] = enum_hal_versions 283*b9df5ad1SAndroid Build Coastguard Worker d['enum_aconfig_flags'] = enum_aconfig_flags 284*b9df5ad1SAndroid Build Coastguard Worker d['enum'] = True 285*b9df5ad1SAndroid Build Coastguard Worker 286*b9df5ad1SAndroid Build Coastguard Worker # 287*b9df5ad1SAndroid Build Coastguard Worker # Container (Array/Tuple) 288*b9df5ad1SAndroid Build Coastguard Worker # 289*b9df5ad1SAndroid Build Coastguard Worker if entry.attrs.get('container') is not None: 290*b9df5ad1SAndroid Build Coastguard Worker container_name = entry['container'] 291*b9df5ad1SAndroid Build Coastguard Worker 292*b9df5ad1SAndroid Build Coastguard Worker array = entry.find('array') 293*b9df5ad1SAndroid Build Coastguard Worker if array is not None: 294*b9df5ad1SAndroid Build Coastguard Worker array_sizes = [] 295*b9df5ad1SAndroid Build Coastguard Worker for size in array.find_all('size'): 296*b9df5ad1SAndroid Build Coastguard Worker array_sizes.append(size.string) 297*b9df5ad1SAndroid Build Coastguard Worker d['container_sizes'] = array_sizes 298*b9df5ad1SAndroid Build Coastguard Worker 299*b9df5ad1SAndroid Build Coastguard Worker tupl = entry.find('tuple') 300*b9df5ad1SAndroid Build Coastguard Worker if tupl is not None: 301*b9df5ad1SAndroid Build Coastguard Worker tupl_values = [] 302*b9df5ad1SAndroid Build Coastguard Worker for val in tupl.find_all('value'): 303*b9df5ad1SAndroid Build Coastguard Worker tupl_values.append(val.name) 304*b9df5ad1SAndroid Build Coastguard Worker d['tuple_values'] = tupl_values 305*b9df5ad1SAndroid Build Coastguard Worker d['container_sizes'] = len(tupl_values) 306*b9df5ad1SAndroid Build Coastguard Worker 307*b9df5ad1SAndroid Build Coastguard Worker d['container'] = container_name 308*b9df5ad1SAndroid Build Coastguard Worker 309*b9df5ad1SAndroid Build Coastguard Worker return d 310*b9df5ad1SAndroid Build Coastguard Worker 311*b9df5ad1SAndroid Build Coastguard Worker def _parse_entry_optional(self, entry): 312*b9df5ad1SAndroid Build Coastguard Worker d = {} 313*b9df5ad1SAndroid Build Coastguard Worker 314*b9df5ad1SAndroid Build Coastguard Worker optional_elements = ['description', 'range', 'units', 'details', 'hal_details', 'ndk_details',\ 315*b9df5ad1SAndroid Build Coastguard Worker 'deprecation_description'] 316*b9df5ad1SAndroid Build Coastguard Worker for i in optional_elements: 317*b9df5ad1SAndroid Build Coastguard Worker prop = find_child_tag(entry, i) 318*b9df5ad1SAndroid Build Coastguard Worker 319*b9df5ad1SAndroid Build Coastguard Worker if prop is not None: 320*b9df5ad1SAndroid Build Coastguard Worker d[i] = prop.string 321*b9df5ad1SAndroid Build Coastguard Worker 322*b9df5ad1SAndroid Build Coastguard Worker tag_ids = [] 323*b9df5ad1SAndroid Build Coastguard Worker for tag in entry.find_all('tag'): 324*b9df5ad1SAndroid Build Coastguard Worker tag_ids.append(tag['id']) 325*b9df5ad1SAndroid Build Coastguard Worker 326*b9df5ad1SAndroid Build Coastguard Worker d['tag_ids'] = tag_ids 327*b9df5ad1SAndroid Build Coastguard Worker 328*b9df5ad1SAndroid Build Coastguard Worker return d 329*b9df5ad1SAndroid Build Coastguard Worker 330*b9df5ad1SAndroid Build Coastguard Worker def render(self, template, output_name=None, enum=None, 331*b9df5ad1SAndroid Build Coastguard Worker copyright_year=None): 332*b9df5ad1SAndroid Build Coastguard Worker """ 333*b9df5ad1SAndroid Build Coastguard Worker Render the metadata model using a Mako template as the view. 334*b9df5ad1SAndroid Build Coastguard Worker 335*b9df5ad1SAndroid Build Coastguard Worker The template gets the metadata as an argument, as well as all 336*b9df5ad1SAndroid Build Coastguard Worker public attributes from the metadata_helpers module. 337*b9df5ad1SAndroid Build Coastguard Worker 338*b9df5ad1SAndroid Build Coastguard Worker The output file is encoded with UTF-8. 339*b9df5ad1SAndroid Build Coastguard Worker 340*b9df5ad1SAndroid Build Coastguard Worker Args: 341*b9df5ad1SAndroid Build Coastguard Worker template: path to a Mako template file 342*b9df5ad1SAndroid Build Coastguard Worker output_name: path to the output file, or None to use stdout 343*b9df5ad1SAndroid Build Coastguard Worker enum: The name of the enum, if any 344*b9df5ad1SAndroid Build Coastguard Worker copyright_year: the year in the copyright section of output file 345*b9df5ad1SAndroid Build Coastguard Worker """ 346*b9df5ad1SAndroid Build Coastguard Worker buf = StringIO() 347*b9df5ad1SAndroid Build Coastguard Worker metadata_helpers._context_buf = buf 348*b9df5ad1SAndroid Build Coastguard Worker metadata_helpers._enum = enum 349*b9df5ad1SAndroid Build Coastguard Worker 350*b9df5ad1SAndroid Build Coastguard Worker copyright_year = copyright_year \ 351*b9df5ad1SAndroid Build Coastguard Worker if copyright_year is not None \ 352*b9df5ad1SAndroid Build Coastguard Worker else str(datetime.now().year) 353*b9df5ad1SAndroid Build Coastguard Worker metadata_helpers._copyright_year = \ 354*b9df5ad1SAndroid Build Coastguard Worker metadata_helpers.infer_copyright_year_from_source(output_name, 355*b9df5ad1SAndroid Build Coastguard Worker copyright_year) 356*b9df5ad1SAndroid Build Coastguard Worker 357*b9df5ad1SAndroid Build Coastguard Worker helpers = [(i, getattr(metadata_helpers, i)) 358*b9df5ad1SAndroid Build Coastguard Worker for i in dir(metadata_helpers) if not i.startswith('_')] 359*b9df5ad1SAndroid Build Coastguard Worker helpers = dict(helpers) 360*b9df5ad1SAndroid Build Coastguard Worker 361*b9df5ad1SAndroid Build Coastguard Worker lookup = TemplateLookup(directories=[os.getcwd()]) 362*b9df5ad1SAndroid Build Coastguard Worker tpl = Template(filename=template, lookup=lookup) 363*b9df5ad1SAndroid Build Coastguard Worker 364*b9df5ad1SAndroid Build Coastguard Worker ctx = Context(buf, metadata=self.metadata, **helpers) 365*b9df5ad1SAndroid Build Coastguard Worker tpl.render_context(ctx) 366*b9df5ad1SAndroid Build Coastguard Worker 367*b9df5ad1SAndroid Build Coastguard Worker tpl_data = buf.getvalue() 368*b9df5ad1SAndroid Build Coastguard Worker metadata_helpers._context_buf = None 369*b9df5ad1SAndroid Build Coastguard Worker buf.close() 370*b9df5ad1SAndroid Build Coastguard Worker 371*b9df5ad1SAndroid Build Coastguard Worker if output_name is None: 372*b9df5ad1SAndroid Build Coastguard Worker print(tpl_data) 373*b9df5ad1SAndroid Build Coastguard Worker else: 374*b9df5ad1SAndroid Build Coastguard Worker open(output_name, "w").write(tpl_data) 375*b9df5ad1SAndroid Build Coastguard Worker 376*b9df5ad1SAndroid Build Coastguard Worker##################### 377*b9df5ad1SAndroid Build Coastguard Worker##################### 378*b9df5ad1SAndroid Build Coastguard Worker 379*b9df5ad1SAndroid Build Coastguard Workerif __name__ == "__main__": 380*b9df5ad1SAndroid Build Coastguard Worker if len(sys.argv) <= 2: 381*b9df5ad1SAndroid Build Coastguard Worker print("Usage: %s <filename.xml> <template.mako> [<output_file>]"\ 382*b9df5ad1SAndroid Build Coastguard Worker " [<copyright_year>]" \ 383*b9df5ad1SAndroid Build Coastguard Worker % (sys.argv[0]), file=sys.stderr) 384*b9df5ad1SAndroid Build Coastguard Worker sys.exit(0) 385*b9df5ad1SAndroid Build Coastguard Worker 386*b9df5ad1SAndroid Build Coastguard Worker file_name = sys.argv[1] 387*b9df5ad1SAndroid Build Coastguard Worker template_name = sys.argv[2] 388*b9df5ad1SAndroid Build Coastguard Worker output_name = sys.argv[3] if len(sys.argv) > 3 else None 389*b9df5ad1SAndroid Build Coastguard Worker copyright_year = sys.argv[4] if len(sys.argv) > 4 else str(datetime.now().year) 390*b9df5ad1SAndroid Build Coastguard Worker 391*b9df5ad1SAndroid Build Coastguard Worker parser = MetadataParserXml.create_from_file(file_name) 392*b9df5ad1SAndroid Build Coastguard Worker parser.render(template_name, output_name, None, copyright_year) 393*b9df5ad1SAndroid Build Coastguard Worker 394*b9df5ad1SAndroid Build Coastguard Worker sys.exit(0) 395