1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import os 6import re 7import sys 8 9import idl_schema 10import json_schema 11from cpp_namespace_environment import CppNamespaceEnvironment 12from model import Model, UnixName 13 14def GenerateFilenames(full_namespace): 15 # Try to find the file defining the namespace. Eg. for 16 # nameSpace.sub_name_space.Type' the following heuristics looks for: 17 # 1. name_space_sub_name_space.json, 18 # 2. name_space_sub_name_space.idl, 19 # 3. sub_name_space.json, 20 # 4. sub_name_space.idl, 21 # 5. etc. 22 sub_namespaces = full_namespace.split('.') 23 filenames = [ ] 24 basename = None 25 for namespace in reversed(sub_namespaces): 26 if basename is not None: 27 basename = UnixName(namespace + '.' + basename) 28 else: 29 basename = UnixName(namespace) 30 for ext in ['json', 'idl']: 31 filenames.append('%s.%s' % (basename, ext)) 32 return filenames 33 34class SchemaLoader(object): 35 '''Resolves a type name into the namespace the type belongs to. 36 37 Properties: 38 - |root| path to the root directory. 39 - |path| path to the directory with the API header files, relative to the 40 root. 41 - |include_rules| List containing tuples with (path, cpp_namespace_pattern) 42 used when searching for types. 43 - |cpp_namespace_pattern| Default namespace pattern 44 ''' 45 def __init__(self, 46 root, 47 path, 48 include_rules, 49 cpp_namespace_pattern): 50 self._root = root 51 self._include_rules = [(path, cpp_namespace_pattern)] 52 self._include_rules.extend(include_rules) 53 54 def ResolveNamespace(self, full_namespace): 55 filenames = GenerateFilenames(full_namespace) 56 for path, cpp_namespace in self._include_rules: 57 for filename in reversed(filenames): 58 filepath = os.path.join(path, filename); 59 if os.path.exists(os.path.join(self._root, filepath)): 60 return Model().AddNamespace( 61 self.LoadSchema(filepath)[0], 62 filepath, 63 environment=CppNamespaceEnvironment(cpp_namespace)) 64 return None 65 66 def ResolveType(self, full_name, default_namespace): 67 name_parts = full_name.rsplit('.', 1) 68 if len(name_parts) == 1: 69 if full_name not in default_namespace.types: 70 return None 71 return default_namespace 72 full_namespace, type_name = full_name.rsplit('.', 1) 73 namespace = self.ResolveNamespace(full_namespace) 74 if namespace and type_name in namespace.types: 75 return namespace 76 return None 77 78 def LoadSchema(self, schema): 79 '''Load a schema definition. The schema parameter must be a file name 80 with the full path relative to the root.''' 81 schema_filename, schema_extension = os.path.splitext(schema) 82 83 schema_path = os.path.join(self._root, schema) 84 if schema_extension == '.json': 85 api_defs = json_schema.Load(schema_path) 86 elif schema_extension == '.idl': 87 api_defs = idl_schema.Load(schema_path) 88 else: 89 sys.exit('Did not recognize file extension %s for schema %s' % 90 (schema_extension, schema)) 91 92 return api_defs 93