| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import copy | 5 import copy |
| 6 import json | 6 import json |
| 7 import logging |
| 7 import os | 8 import os |
| 8 | 9 |
| 9 from docs_server_utils import GetLinkToRefType | |
| 10 import compiled_file_system as compiled_fs | 10 import compiled_file_system as compiled_fs |
| 11 from file_system import FileNotFoundError | 11 from file_system import FileNotFoundError |
| 12 import third_party.json_schema_compiler.json_comment_eater as json_comment_eater | 12 import third_party.json_schema_compiler.json_comment_eater as json_comment_eater |
| 13 import third_party.json_schema_compiler.model as model | 13 import third_party.json_schema_compiler.model as model |
| 14 import third_party.json_schema_compiler.idl_schema as idl_schema | 14 import third_party.json_schema_compiler.idl_schema as idl_schema |
| 15 import third_party.json_schema_compiler.idl_parser as idl_parser | 15 import third_party.json_schema_compiler.idl_parser as idl_parser |
| 16 | 16 |
| 17 # Increment this version when there are changes to the data stored in any of | 17 # Increment this version when there are changes to the data stored in any of |
| 18 # the caches used by APIDataSource. This allows the cache to be invalidated | 18 # the caches used by APIDataSource. This allows the cache to be invalidated |
| 19 # without having to flush memcache on the production server. | 19 # without having to flush memcache on the production server. |
| 20 _VERSION = 2 | 20 _VERSION = 3 |
| 21 | 21 |
| 22 def _RemoveNoDocs(item): | 22 def _RemoveNoDocs(item): |
| 23 if type(item) == dict: | 23 if type(item) == dict: |
| 24 if item.get('nodoc', False): | 24 if item.get('nodoc', False): |
| 25 return True | 25 return True |
| 26 to_remove = [] | 26 to_remove = [] |
| 27 for key, value in item.items(): | 27 for key, value in item.items(): |
| 28 if _RemoveNoDocs(value): | 28 if _RemoveNoDocs(value): |
| 29 to_remove.append(key) | 29 to_remove.append(key) |
| 30 for k in to_remove: | 30 for k in to_remove: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 42 if node.parent is not None and not isinstance(node.parent, model.Namespace): | 42 if node.parent is not None and not isinstance(node.parent, model.Namespace): |
| 43 return '-'.join([prefix, node.parent.simple_name, node.simple_name]) | 43 return '-'.join([prefix, node.parent.simple_name, node.simple_name]) |
| 44 return '-'.join([prefix, node.simple_name]) | 44 return '-'.join([prefix, node.simple_name]) |
| 45 | 45 |
| 46 def _FormatValue(value): | 46 def _FormatValue(value): |
| 47 """Inserts commas every three digits for integer values. It is magic. | 47 """Inserts commas every three digits for integer values. It is magic. |
| 48 """ | 48 """ |
| 49 s = str(value) | 49 s = str(value) |
| 50 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) | 50 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) |
| 51 | 51 |
| 52 class _JscModel(object): | 52 class _JSCModel(object): |
| 53 """Uses a Model from the JSON Schema Compiler and generates a dict that | 53 """Uses a Model from the JSON Schema Compiler and generates a dict that |
| 54 a Handlebar template can use for a data source. | 54 a Handlebar template can use for a data source. |
| 55 """ | 55 """ |
| 56 def __init__(self, json): | 56 def __init__(self, json, ref_resolver, disable_refs): |
| 57 self._ref_resolver = ref_resolver |
| 58 self._disable_refs = disable_refs |
| 57 clean_json = copy.deepcopy(json) | 59 clean_json = copy.deepcopy(json) |
| 58 if _RemoveNoDocs(clean_json): | 60 if _RemoveNoDocs(clean_json): |
| 59 self._namespace = None | 61 self._namespace = None |
| 60 else: | 62 else: |
| 61 self._namespace = model.Namespace(clean_json, clean_json['namespace']) | 63 self._namespace = model.Namespace(clean_json, clean_json['namespace']) |
| 62 | 64 |
| 65 def _GetLink(self, ref): |
| 66 if not self._disable_refs: |
| 67 ref_data = self._ref_resolver.GetLink(self._namespace.name, ref) |
| 68 if ref_data is not None: |
| 69 return ref_data |
| 70 logging.error('$ref %s could not be resolved.' % ref) |
| 71 if '.' in ref: |
| 72 type_name = ref.rsplit('.', 1)[-1] |
| 73 else: |
| 74 type_name = ref |
| 75 return { 'href': '#type-%s' % type_name, 'text': ref } |
| 76 |
| 63 def _FormatDescription(self, description): | 77 def _FormatDescription(self, description): |
| 64 if description is None or '$ref:' not in description: | 78 if description is None or '$ref:' not in description: |
| 65 return description | 79 return description |
| 66 refs = description.split('$ref:') | 80 refs = description.split('$ref:') |
| 67 formatted_description = [refs[0]] | 81 formatted_description = [refs[0]] |
| 68 for ref in refs[1:]: | 82 for ref in refs[1:]: |
| 69 parts = ref.split(' ', 1) | 83 parts = ref.split(' ', 1) |
| 70 if len(parts) == 1: | 84 if len(parts) == 1: |
| 71 ref = parts[0] | 85 ref = parts[0] |
| 72 rest = '' | 86 rest = '' |
| 73 else: | 87 else: |
| 74 ref, rest = parts | 88 ref, rest = parts |
| 75 rest = ' ' + rest | 89 rest = ' ' + rest |
| 76 if not ref[-1].isalnum(): | 90 if not ref[-1].isalnum(): |
| 77 rest = ref[-1] + rest | 91 rest = ref[-1] + rest |
| 78 ref = ref[:-1] | 92 ref = ref[:-1] |
| 79 ref_dict = GetLinkToRefType(self._namespace.name, ref) | 93 ref_dict = self._GetLink(ref) |
| 80 formatted_description.append('<a href="%(href)s">%(text)s</a>%(rest)s' % | 94 formatted_description.append('<a href="%(href)s">%(text)s</a>%(rest)s' % |
| 81 { 'href': ref_dict['href'], 'text': ref_dict['text'], 'rest': rest }) | 95 { 'href': ref_dict['href'], 'text': ref_dict['text'], 'rest': rest }) |
| 82 return ''.join(formatted_description) | 96 return ''.join(formatted_description) |
| 83 | 97 |
| 84 def ToDict(self): | 98 def ToDict(self): |
| 85 if self._namespace is None: | 99 if self._namespace is None: |
| 86 return {} | 100 return {} |
| 87 return { | 101 return { |
| 88 'name': self._namespace.name, | 102 'name': self._namespace.name, |
| 89 'types': [self._GenerateType(t) for t in self._namespace.types.values() | 103 'types': [self._GenerateType(t) for t in self._namespace.types.values() |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 function_dict['parameters'][-1]['last'] = True | 146 function_dict['parameters'][-1]['last'] = True |
| 133 return function_dict | 147 return function_dict |
| 134 | 148 |
| 135 def _GenerateEvents(self, events): | 149 def _GenerateEvents(self, events): |
| 136 return [self._GenerateEvent(e) for e in events.values()] | 150 return [self._GenerateEvent(e) for e in events.values()] |
| 137 | 151 |
| 138 def _GenerateEvent(self, event): | 152 def _GenerateEvent(self, event): |
| 139 event_dict = { | 153 event_dict = { |
| 140 'name': event.simple_name, | 154 'name': event.simple_name, |
| 141 'description': self._FormatDescription(event.description), | 155 'description': self._FormatDescription(event.description), |
| 142 'parameters': map(self._GenerateProperty, event.params), | 156 'parameters': [self._GenerateProperty(p) for p in event.params], |
| 143 'callback': self._GenerateCallback(event.callback), | 157 'callback': self._GenerateCallback(event.callback), |
| 144 'conditions': [GetLinkToRefType(self._namespace.name, c) | 158 'filters': [self._GenerateProperty(f) for f in event.filters], |
| 145 for c in event.conditions], | 159 'conditions': [self._GetLink(condition) |
| 146 'actions': [GetLinkToRefType(self._namespace.name, a) | 160 for condition in event.conditions], |
| 147 for a in event.actions], | 161 'actions': [self._GetLink(action) for action in event.actions], |
| 148 'filters': map(self._GenerateProperty, event.filters), | |
| 149 'supportsRules': event.supports_rules, | 162 'supportsRules': event.supports_rules, |
| 150 'id': _CreateId(event, 'event') | 163 'id': _CreateId(event, 'event') |
| 151 } | 164 } |
| 152 if (event.parent is not None and | 165 if (event.parent is not None and |
| 153 not isinstance(event.parent, model.Namespace)): | 166 not isinstance(event.parent, model.Namespace)): |
| 154 event_dict['parent_name'] = event.parent.simple_name | 167 event_dict['parent_name'] = event.parent.simple_name |
| 155 else: | 168 else: |
| 156 event_dict['parent_name'] = None | 169 event_dict['parent_name'] = None |
| 157 if event_dict['callback']: | 170 if event_dict['callback']: |
| 158 event_dict['parameters'].append(event_dict['callback']) | 171 event_dict['parameters'].append(event_dict['callback']) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 179 def _GenerateProperties(self, properties): | 192 def _GenerateProperties(self, properties): |
| 180 return [self._GenerateProperty(v) for v in properties.values() | 193 return [self._GenerateProperty(v) for v in properties.values() |
| 181 if v.type_ != model.PropertyType.ADDITIONAL_PROPERTIES] | 194 if v.type_ != model.PropertyType.ADDITIONAL_PROPERTIES] |
| 182 | 195 |
| 183 def _GenerateProperty(self, property_): | 196 def _GenerateProperty(self, property_): |
| 184 property_dict = { | 197 property_dict = { |
| 185 'name': property_.simple_name, | 198 'name': property_.simple_name, |
| 186 'optional': property_.optional, | 199 'optional': property_.optional, |
| 187 'description': self._FormatDescription(property_.description), | 200 'description': self._FormatDescription(property_.description), |
| 188 'properties': self._GenerateProperties(property_.properties), | 201 'properties': self._GenerateProperties(property_.properties), |
| 202 'functions': self._GenerateFunctions(property_.functions), |
| 189 'parameters': [], | 203 'parameters': [], |
| 190 'functions': self._GenerateFunctions(property_.functions), | |
| 191 'returns': None, | 204 'returns': None, |
| 192 'id': _CreateId(property_, 'property') | 205 'id': _CreateId(property_, 'property') |
| 193 } | 206 } |
| 194 for param in property_.params: | 207 for param in property_.params: |
| 195 property_dict['parameters'].append(self._GenerateProperty(param)) | 208 property_dict['parameters'].append(self._GenerateProperty(param)) |
| 196 if property_.returns: | 209 if property_.returns: |
| 197 property_dict['returns'] = self._GenerateProperty(property_.returns) | 210 property_dict['returns'] = self._GenerateProperty(property_.returns) |
| 198 if (property_.parent is not None and | 211 if (property_.parent is not None and |
| 199 not isinstance(property_.parent, model.Namespace)): | 212 not isinstance(property_.parent, model.Namespace)): |
| 200 property_dict['parent_name'] = property_.parent.simple_name | 213 property_dict['parent_name'] = property_.parent.simple_name |
| 201 else: | 214 else: |
| 202 property_dict['parent_name'] = None | 215 property_dict['parent_name'] = None |
| 203 if property_.has_value: | 216 if property_.has_value: |
| 204 if isinstance(property_.value, int): | 217 if isinstance(property_.value, int): |
| 205 property_dict['value'] = _FormatValue(property_.value) | 218 property_dict['value'] = _FormatValue(property_.value) |
| 206 else: | 219 else: |
| 207 property_dict['value'] = property_.value | 220 property_dict['value'] = property_.value |
| 208 else: | 221 else: |
| 209 self._RenderTypeInformation(property_, property_dict) | 222 self._RenderTypeInformation(property_, property_dict) |
| 210 return property_dict | 223 return property_dict |
| 211 | 224 |
| 212 def _RenderTypeInformation(self, property_, dst_dict): | 225 def _RenderTypeInformation(self, property_, dst_dict): |
| 213 if property_.type_ == model.PropertyType.CHOICES: | 226 if property_.type_ == model.PropertyType.CHOICES: |
| 214 dst_dict['choices'] = map(self._GenerateProperty, | 227 dst_dict['choices'] = [self._GenerateProperty(c) |
| 215 property_.choices.values()) | 228 for c in property_.choices.values()] |
| 216 # We keep track of which is last for knowing when to add "or" between | 229 # We keep track of which is last for knowing when to add "or" between |
| 217 # choices in templates. | 230 # choices in templates. |
| 218 if len(dst_dict['choices']) > 0: | 231 if len(dst_dict['choices']) > 0: |
| 219 dst_dict['choices'][-1]['last'] = True | 232 dst_dict['choices'][-1]['last'] = True |
| 220 elif property_.type_ == model.PropertyType.REF: | 233 elif property_.type_ == model.PropertyType.REF: |
| 221 dst_dict['link'] = GetLinkToRefType(self._namespace.name, | 234 dst_dict['link'] = self._GetLink(property_.ref_type) |
| 222 property_.ref_type) | |
| 223 elif property_.type_ == model.PropertyType.ARRAY: | 235 elif property_.type_ == model.PropertyType.ARRAY: |
| 224 dst_dict['array'] = self._GenerateProperty(property_.item_type) | 236 dst_dict['array'] = self._GenerateProperty(property_.item_type) |
| 225 elif property_.type_ == model.PropertyType.ENUM: | 237 elif property_.type_ == model.PropertyType.ENUM: |
| 226 dst_dict['enum_values'] = [] | 238 dst_dict['enum_values'] = [] |
| 227 for enum_value in property_.enum_values: | 239 for enum_value in property_.enum_values: |
| 228 dst_dict['enum_values'].append({'name': enum_value}) | 240 dst_dict['enum_values'].append({'name': enum_value}) |
| 229 if len(dst_dict['enum_values']) > 0: | 241 if len(dst_dict['enum_values']) > 0: |
| 230 dst_dict['enum_values'][-1]['last'] = True | 242 dst_dict['enum_values'][-1]['last'] = True |
| 231 elif property_.instance_of is not None: | 243 elif property_.instance_of is not None: |
| 232 dst_dict['simple_type'] = property_.instance_of.lower() | 244 dst_dict['simple_type'] = property_.instance_of.lower() |
| 233 else: | 245 else: |
| 234 dst_dict['simple_type'] = property_.type_.name.lower() | 246 dst_dict['simple_type'] = property_.type_.name.lower() |
| 235 | 247 |
| 236 class _LazySamplesGetter(object): | 248 class _LazySamplesGetter(object): |
| 237 """This class is needed so that an extensions API page does not have to fetch | 249 """This class is needed so that an extensions API page does not have to fetch |
| 238 the apps samples page and vice versa. | 250 the apps samples page and vice versa. |
| 239 """ | 251 """ |
| 240 def __init__(self, api_name, samples): | 252 def __init__(self, api_name, samples): |
| 241 self._api_name = api_name | 253 self._api_name = api_name |
| 242 self._samples = samples | 254 self._samples = samples |
| 243 | 255 |
| 244 def get(self, key): | 256 def get(self, key): |
| 245 return self._samples.FilterSamples(key, self._api_name) | 257 return self._samples.FilterSamples(key, self._api_name) |
| 246 | 258 |
| 247 class APIDataSource(object): | 259 class APIDataSource(object): |
| 248 """This class fetches and loads JSON APIs from the FileSystem passed in with | 260 """This class fetches and loads JSON APIs from the FileSystem passed in with |
| 249 |cache_factory|, so the APIs can be plugged into templates. | 261 |cache_factory|, so the APIs can be plugged into templates. |
| 250 """ | 262 """ |
| 251 class Factory(object): | 263 class Factory(object): |
| 252 def __init__(self, cache_factory, base_path, samples_factory): | 264 def __init__(self, |
| 265 cache_factory, |
| 266 base_path): |
| 253 self._permissions_cache = cache_factory.Create(self._LoadPermissions, | 267 self._permissions_cache = cache_factory.Create(self._LoadPermissions, |
| 254 compiled_fs.PERMS, | 268 compiled_fs.PERMS, |
| 255 version=_VERSION) | 269 version=_VERSION) |
| 256 self._json_cache = cache_factory.Create(self._LoadJsonAPI, | 270 self._json_cache = cache_factory.Create( |
| 257 compiled_fs.JSON, | 271 lambda api: self._LoadJsonAPI(api, False), |
| 258 version=_VERSION) | 272 compiled_fs.JSON, |
| 259 self._idl_cache = cache_factory.Create(self._LoadIdlAPI, | 273 version=_VERSION) |
| 260 compiled_fs.IDL, | 274 self._idl_cache = cache_factory.Create( |
| 261 version=_VERSION) | 275 lambda api: self._LoadIdlAPI(api, False), |
| 276 compiled_fs.IDL, |
| 277 version=_VERSION) |
| 278 |
| 279 # These caches are used if an APIDataSource does not want to resolve the |
| 280 # $refs in an API. This is needed to prevent infinite recursion in |
| 281 # ReferenceResolver. |
| 282 self._json_cache_no_refs = cache_factory.Create( |
| 283 lambda api: self._LoadJsonAPI(api, True), |
| 284 compiled_fs.JSON_NO_REFS, |
| 285 version=_VERSION) |
| 286 self._idl_cache_no_refs = cache_factory.Create( |
| 287 lambda api: self._LoadIdlAPI(api, True), |
| 288 compiled_fs.IDL_NO_REFS, |
| 289 version=_VERSION) |
| 262 self._idl_names_cache = cache_factory.Create(self._GetIDLNames, | 290 self._idl_names_cache = cache_factory.Create(self._GetIDLNames, |
| 263 compiled_fs.IDL_NAMES, | 291 compiled_fs.IDL_NAMES, |
| 264 version=_VERSION) | 292 version=_VERSION) |
| 265 self._samples_factory = samples_factory | 293 self._names_cache = cache_factory.Create(self._GetAllNames, |
| 294 compiled_fs.NAMES, |
| 295 version=_VERSION) |
| 266 self._base_path = base_path | 296 self._base_path = base_path |
| 267 | 297 |
| 268 def Create(self, request): | 298 # These must be set later via the SetFooDataSourceFactory methods. |
| 299 self._ref_resolver_factory = None |
| 300 self._samples_data_source_factory = None |
| 301 |
| 302 def SetSamplesDataSourceFactory(self, samples_data_source_factory): |
| 303 self._samples_data_source_factory = samples_data_source_factory |
| 304 |
| 305 def SetReferenceResolverFactory(self, ref_resolver_factory): |
| 306 self._ref_resolver_factory = ref_resolver_factory |
| 307 |
| 308 def Create(self, request, disable_refs=False): |
| 309 """Create an APIDataSource. |disable_refs| specifies whether $ref's in |
| 310 APIs being processed by the |ToDict| method of _JSCModel follows $ref's |
| 311 in the API. This prevents endless recursion in ReferenceResolver. |
| 312 """ |
| 313 if self._samples_data_source_factory is None: |
| 314 # Only error if there is a request, which means this APIDataSource is |
| 315 # actually being used to render a page. |
| 316 if request is not None: |
| 317 logging.error('SamplesDataSource.Factory was never set in ' |
| 318 'APIDataSource.Factory.') |
| 319 samples = None |
| 320 else: |
| 321 samples = self._samples_data_source_factory.Create(request) |
| 322 if not disable_refs and self._ref_resolver_factory is None: |
| 323 logging.error('ReferenceResolver.Factory was never set in ' |
| 324 'APIDataSource.Factory.') |
| 269 return APIDataSource(self._permissions_cache, | 325 return APIDataSource(self._permissions_cache, |
| 270 self._json_cache, | 326 self._json_cache, |
| 271 self._idl_cache, | 327 self._idl_cache, |
| 328 self._json_cache_no_refs, |
| 329 self._idl_cache_no_refs, |
| 330 self._names_cache, |
| 272 self._idl_names_cache, | 331 self._idl_names_cache, |
| 273 self._base_path, | 332 self._base_path, |
| 274 self._samples_factory.Create(request)) | 333 samples, |
| 334 disable_refs) |
| 275 | 335 |
| 276 def _LoadPermissions(self, json_str): | 336 def _LoadPermissions(self, json_str): |
| 277 return json.loads(json_comment_eater.Nom(json_str)) | 337 return json.loads(json_comment_eater.Nom(json_str)) |
| 278 | 338 |
| 279 def _LoadJsonAPI(self, api): | 339 def _LoadJsonAPI(self, api, disable_refs): |
| 280 return _JscModel(json.loads(json_comment_eater.Nom(api))[0]) | 340 return _JSCModel( |
| 341 json.loads(json_comment_eater.Nom(api))[0], |
| 342 self._ref_resolver_factory.Create() if not disable_refs else None, |
| 343 disable_refs).ToDict() |
| 281 | 344 |
| 282 def _LoadIdlAPI(self, api): | 345 def _LoadIdlAPI(self, api, disable_refs): |
| 283 idl = idl_parser.IDLParser().ParseData(api) | 346 idl = idl_parser.IDLParser().ParseData(api) |
| 284 return _JscModel(idl_schema.IDLSchema(idl).process()[0]) | 347 return _JSCModel( |
| 348 idl_schema.IDLSchema(idl).process()[0], |
| 349 self._ref_resolver_factory.Create() if not disable_refs else None, |
| 350 disable_refs).ToDict() |
| 285 | 351 |
| 286 def _GetIDLNames(self, apis): | 352 def _GetIDLNames(self, apis): |
| 287 return [model.UnixName(os.path.splitext(api.split('/')[-1])[0]) | 353 return [ |
| 288 for api in apis if api.endswith('.idl')] | 354 model.UnixName(os.path.splitext(api[len('%s/' % self._base_path):])[0]) |
| 355 for api in apis if api.endswith('.idl') |
| 356 ] |
| 357 |
| 358 def _GetAllNames(self, apis): |
| 359 return [ |
| 360 model.UnixName(os.path.splitext(api[len('%s/' % self._base_path):])[0]) |
| 361 for api in apis |
| 362 ] |
| 289 | 363 |
| 290 def __init__(self, | 364 def __init__(self, |
| 291 permissions_cache, | 365 permissions_cache, |
| 292 json_cache, | 366 json_cache, |
| 293 idl_cache, | 367 idl_cache, |
| 368 json_cache_no_refs, |
| 369 idl_cache_no_refs, |
| 370 names_cache, |
| 294 idl_names_cache, | 371 idl_names_cache, |
| 295 base_path, | 372 base_path, |
| 296 samples): | 373 samples, |
| 374 disable_refs): |
| 297 self._base_path = base_path | 375 self._base_path = base_path |
| 298 self._permissions_cache = permissions_cache | 376 self._permissions_cache = permissions_cache |
| 299 self._json_cache = json_cache | 377 self._json_cache = json_cache |
| 300 self._idl_cache = idl_cache | 378 self._idl_cache = idl_cache |
| 379 self._json_cache_no_refs = json_cache_no_refs |
| 380 self._idl_cache_no_refs = idl_cache_no_refs |
| 381 self._names_cache = names_cache |
| 301 self._idl_names_cache = idl_names_cache | 382 self._idl_names_cache = idl_names_cache |
| 302 self._samples = samples | 383 self._samples = samples |
| 384 self._disable_refs = disable_refs |
| 303 | 385 |
| 304 def _GetPermsFromFile(self, filename): | 386 def _GetPermsFromFile(self, filename): |
| 305 try: | 387 try: |
| 306 perms = self._permissions_cache.GetFromFile('%s/%s' % | 388 perms = self._permissions_cache.GetFromFile('%s/%s' % |
| 307 (self._base_path, filename)) | 389 (self._base_path, filename)) |
| 308 return dict((model.UnixName(k), v) for k, v in perms.iteritems()) | 390 return dict((model.UnixName(k), v) for k, v in perms.iteritems()) |
| 309 except FileNotFoundError: | 391 except FileNotFoundError: |
| 310 return {} | 392 return {} |
| 311 | 393 |
| 312 def _GetFeature(self, path): | 394 def _GetFeature(self, path): |
| 313 # Remove 'experimental_' from path name to match the keys in | 395 # Remove 'experimental_' from path name to match the keys in |
| 314 # _permissions_features.json. | 396 # _permissions_features.json. |
| 315 path = model.UnixName(path.replace('experimental_', '')) | 397 path = model.UnixName(path.replace('experimental_', '')) |
| 316 for filename in ['_permission_features.json', '_manifest_features.json']: | 398 for filename in ['_permission_features.json', '_manifest_features.json']: |
| 317 api_perms = self._GetPermsFromFile(filename).get(path, None) | 399 api_perms = self._GetPermsFromFile(filename).get(path, None) |
| 318 if api_perms is not None: | 400 if api_perms is not None: |
| 319 break | 401 break |
| 320 if api_perms and api_perms['channel'] in ('trunk', 'dev', 'beta'): | 402 if api_perms and api_perms['channel'] in ('trunk', 'dev', 'beta'): |
| 321 api_perms[api_perms['channel']] = True | 403 api_perms[api_perms['channel']] = True |
| 322 return api_perms | 404 return api_perms |
| 323 | 405 |
| 324 def _GenerateHandlebarContext(self, handlebar, path): | 406 def _GenerateHandlebarContext(self, handlebar_dict, path): |
| 325 return_dict = { | 407 return_dict = { |
| 326 'permissions': self._GetFeature(path), | 408 'permissions': self._GetFeature(path), |
| 327 'samples': _LazySamplesGetter(path, self._samples) | 409 'samples': _LazySamplesGetter(path, self._samples) |
| 328 } | 410 } |
| 329 return_dict.update(handlebar.ToDict()) | 411 return_dict.update(handlebar_dict) |
| 330 return return_dict | 412 return return_dict |
| 331 | 413 |
| 332 def __getitem__(self, key): | 414 def _GetAsSubdirectory(self, name): |
| 333 return self.get(key) | 415 if name.startswith('experimental_'): |
| 416 parts = name[len('experimental_'):].split('_', 1) |
| 417 parts[1] = 'experimental_%s' % parts[1] |
| 418 return '/'.join(parts) |
| 419 return name.replace('_', '/', 1) |
| 334 | 420 |
| 335 def get(self, key): | 421 def get(self, key): |
| 336 path, ext = os.path.splitext(key) | 422 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): |
| 423 path, ext = os.path.splitext(key) |
| 424 else: |
| 425 path = key |
| 337 unix_name = model.UnixName(path) | 426 unix_name = model.UnixName(path) |
| 338 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path) | 427 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path) |
| 339 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else | 428 names = self._names_cache.GetFromFileListing(self._base_path) |
| 340 (self._json_cache, '.json')) | 429 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: |
| 430 unix_name = self._GetAsSubdirectory(unix_name) |
| 431 |
| 432 if self._disable_refs: |
| 433 cache, ext = ( |
| 434 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else |
| 435 (self._json_cache_no_refs, '.json')) |
| 436 else: |
| 437 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else |
| 438 (self._json_cache, '.json')) |
| 341 return self._GenerateHandlebarContext( | 439 return self._GenerateHandlebarContext( |
| 342 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), | 440 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), |
| 343 path) | 441 path) |
| OLD | NEW |