api_data_source.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import copy
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import compiled_file_system as compiled_fs
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from file_system import FileNotFoundError
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import third_party.json_schema_compiler.json_comment_eater as json_comment_eater
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import third_party.json_schema_compiler.model as model
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import third_party.json_schema_compiler.idl_schema as idl_schema
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import third_party.json_schema_compiler.idl_parser as idl_parser
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Increment this version when there are changes to the data stored in any of
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the caches used by APIDataSource. This allows the cache to be invalidated
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# without having to flush memcache on the production server.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_VERSION = 3
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _RemoveNoDocs(item):
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if type(item) == dict:
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if item.get('nodoc', False):
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to_remove = []
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for key, value in item.items():
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if _RemoveNoDocs(value):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        to_remove.append(key)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for k in to_remove:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      del item[k]
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif type(item) == list:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to_remove = []
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for i in item:
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if _RemoveNoDocs(i):
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        to_remove.append(i)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for i in to_remove:
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item.remove(i)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return False
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _CreateId(node, prefix):
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if node.parent is not None and not isinstance(node.parent, model.Namespace):
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '-'.join([prefix, node.parent.simple_name, node.simple_name])
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return '-'.join([prefix, node.simple_name])
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _FormatValue(value):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Inserts commas every three digits for integer values. It is magic.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s = str(value)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1])
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _JSCModel(object):
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Uses a Model from the JSON Schema Compiler and generates a dict that
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  a Handlebar template can use for a data source.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, json, ref_resolver, disable_refs):
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._ref_resolver = ref_resolver
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._disable_refs = disable_refs
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clean_json = copy.deepcopy(json)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _RemoveNoDocs(clean_json):
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._namespace = None
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._namespace = model.Namespace(clean_json, clean_json['namespace'])
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetLink(self, ref):
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self._disable_refs:
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ref_data = self._ref_resolver.GetLink(self._namespace.name, ref)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ref_data is not None:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ref_data
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.error('$ref %s could not be resolved.' % ref)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '.' in ref:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type_name = ref.rsplit('.', 1)[-1]
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type_name = ref
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return { 'href': '#type-%s' % type_name, 'text': ref }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _FormatDescription(self, description):
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if description is None or '$ref:' not in description:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return description
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    refs = description.split('$ref:')
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    formatted_description = [refs[0]]
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for ref in refs[1:]:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parts = ref.split(' ', 1)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if len(parts) == 1:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ref = parts[0]
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rest = ''
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ref, rest = parts
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rest = ' ' + rest
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not ref[-1].isalnum():
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rest = ref[-1] + rest
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ref = ref[:-1]
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ref_dict = self._GetLink(ref)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      formatted_description.append('<a href="%(href)s">%(text)s</a>%(rest)s' %
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          { 'href': ref_dict['href'], 'text': ref_dict['text'], 'rest': rest })
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''.join(formatted_description)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToDict(self):
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._namespace is None:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return {}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'name': self._namespace.name,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'types':  [self._GenerateType(t) for t in self._namespace.types.values()
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 if t.type_ != model.PropertyType.ADDITIONAL_PROPERTIES],
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'functions': self._GenerateFunctions(self._namespace.functions),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'events': self._GenerateEvents(self._namespace.events),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'properties': self._GenerateProperties(self._namespace.properties)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateType(self, type_):
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type_dict = {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'name': type_.simple_name,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'description': self._FormatDescription(type_.description),
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'properties': self._GenerateProperties(type_.properties),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'functions': self._GenerateFunctions(type_.functions),
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'events': self._GenerateEvents(type_.events),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': _CreateId(type_, 'type')
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._RenderTypeInformation(type_, type_dict)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_dict
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateFunctions(self, functions):
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return [self._GenerateFunction(f) for f in functions.values()]
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateFunction(self, function):
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function_dict = {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'name': function.simple_name,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'description': self._FormatDescription(function.description),
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'callback': self._GenerateCallback(function.callback),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'parameters': [],
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'returns': None,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': _CreateId(function, 'method')
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (function.parent is not None and
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        not isinstance(function.parent, model.Namespace)):
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function_dict['parent_name'] = function.parent.simple_name
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function_dict['parent_name'] = None
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if function.returns:
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function_dict['returns'] = self._GenerateProperty(function.returns)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for param in function.params:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function_dict['parameters'].append(self._GenerateProperty(param))
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if function_dict['callback']:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function_dict['parameters'].append(function_dict['callback'])
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(function_dict['parameters']) > 0:
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function_dict['parameters'][-1]['last'] = True
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return function_dict
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateEvents(self, events):
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return [self._GenerateEvent(e) for e in events.values()]
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateEvent(self, event):
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event_dict = {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'name': event.simple_name,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'description': self._FormatDescription(event.description),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'parameters': [self._GenerateProperty(p) for p in event.params],
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'callback': self._GenerateCallback(event.callback),
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'filters': [self._GenerateProperty(f) for f in event.filters],
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'conditions': [self._GetLink(condition)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     for condition in event.conditions],
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'actions': [self._GetLink(action) for action in event.actions],
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'supportsRules': event.supports_rules,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': _CreateId(event, 'event')
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (event.parent is not None and
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        not isinstance(event.parent, model.Namespace)):
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_dict['parent_name'] = event.parent.simple_name
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_dict['parent_name'] = None
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if event_dict['callback']:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_dict['parameters'].append(event_dict['callback'])
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(event_dict['parameters']) > 0:
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_dict['parameters'][-1]['last'] = True
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return event_dict
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateCallback(self, callback):
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not callback:
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return None
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_dict = {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'name': callback.simple_name,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'description': self._FormatDescription(callback.description),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'simple_type': {'simple_type': 'function'},
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'optional': callback.optional,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'parameters': []
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for param in callback.params:
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_dict['parameters'].append(self._GenerateProperty(param))
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len(callback_dict['parameters']) > 0):
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_dict['parameters'][-1]['last'] = True
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return callback_dict
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateProperties(self, properties):
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return [self._GenerateProperty(v) for v in properties.values()
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if v.type_ != model.PropertyType.ADDITIONAL_PROPERTIES]
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateProperty(self, property_):
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    property_dict = {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'name': property_.simple_name,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'optional': property_.optional,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'description': self._FormatDescription(property_.description),
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'properties': self._GenerateProperties(property_.properties),
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'functions': self._GenerateFunctions(property_.functions),
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'parameters': [],
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'returns': None,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'id': _CreateId(property_, 'property')
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for param in property_.params:
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      property_dict['parameters'].append(self._GenerateProperty(param))
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if property_.returns:
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      property_dict['returns'] = self._GenerateProperty(property_.returns)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (property_.parent is not None and
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        not isinstance(property_.parent, model.Namespace)):
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      property_dict['parent_name'] = property_.parent.simple_name
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      property_dict['parent_name'] = None
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if property_.has_value:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if isinstance(property_.value, int):
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        property_dict['value'] = _FormatValue(property_.value)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        property_dict['value'] = property_.value
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._RenderTypeInformation(property_, property_dict)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return property_dict
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _RenderTypeInformation(self, property_, dst_dict):
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if property_.type_ == model.PropertyType.CHOICES:
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst_dict['choices'] = [self._GenerateProperty(c)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             for c in property_.choices.values()]
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # We keep track of which is last for knowing when to add "or" between
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # choices in templates.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if len(dst_dict['choices']) > 0:
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dst_dict['choices'][-1]['last'] = True
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif property_.type_ == model.PropertyType.REF:
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst_dict['link'] = self._GetLink(property_.ref_type)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif property_.type_ == model.PropertyType.ARRAY:
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst_dict['array'] = self._GenerateProperty(property_.item_type)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif property_.type_ == model.PropertyType.ENUM:
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst_dict['enum_values'] = []
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for enum_value in property_.enum_values:
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dst_dict['enum_values'].append({'name': enum_value})
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if len(dst_dict['enum_values']) > 0:
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dst_dict['enum_values'][-1]['last'] = True
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif property_.instance_of is not None:
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst_dict['simple_type'] = property_.instance_of.lower()
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dst_dict['simple_type'] = property_.type_.name.lower()
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _LazySamplesGetter(object):
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """This class is needed so that an extensions API page does not have to fetch
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  the apps samples page and vice versa.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, api_name, samples):
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._api_name = api_name
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._samples = samples
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def get(self, key):
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._samples.FilterSamples(key, self._api_name)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class APIDataSource(object):
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """This class fetches and loads JSON APIs from the FileSystem passed in with
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  |cache_factory|, so the APIs can be plugged into templates.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class Factory(object):
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def __init__(self,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 cache_factory,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base_path):
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._permissions_cache = cache_factory.Create(self._LoadPermissions,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     compiled_fs.PERMS,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     version=_VERSION)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._json_cache = cache_factory.Create(
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          lambda api: self._LoadJsonAPI(api, False),
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          compiled_fs.JSON,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          version=_VERSION)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._idl_cache = cache_factory.Create(
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          lambda api: self._LoadIdlAPI(api, False),
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          compiled_fs.IDL,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          version=_VERSION)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # These caches are used if an APIDataSource does not want to resolve the
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # $refs in an API. This is needed to prevent infinite recursion in
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # ReferenceResolver.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._json_cache_no_refs = cache_factory.Create(
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          lambda api: self._LoadJsonAPI(api, True),
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          compiled_fs.JSON_NO_REFS,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          version=_VERSION)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._idl_cache_no_refs = cache_factory.Create(
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          lambda api: self._LoadIdlAPI(api, True),
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          compiled_fs.IDL_NO_REFS,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          version=_VERSION)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._idl_names_cache = cache_factory.Create(self._GetIDLNames,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   compiled_fs.IDL_NAMES,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   version=_VERSION)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._names_cache = cache_factory.Create(self._GetAllNames,
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               compiled_fs.NAMES,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               version=_VERSION)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._base_path = base_path
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # These must be set later via the SetFooDataSourceFactory methods.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ref_resolver_factory = None
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._samples_data_source_factory = None
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def SetSamplesDataSourceFactory(self, samples_data_source_factory):
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._samples_data_source_factory = samples_data_source_factory
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def SetReferenceResolverFactory(self, ref_resolver_factory):
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ref_resolver_factory = ref_resolver_factory
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def Create(self, request, disable_refs=False):
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """Create an APIDataSource. |disable_refs| specifies whether $ref's in
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      APIs being processed by the |ToDict| method of _JSCModel follows $ref's
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in the API. This prevents endless recursion in ReferenceResolver.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      """
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._samples_data_source_factory is None:
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Only error if there is a request, which means this APIDataSource is
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # actually being used to render a page.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if request is not None:
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.error('SamplesDataSource.Factory was never set in '
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'APIDataSource.Factory.')
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        samples = None
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        samples = self._samples_data_source_factory.Create(request)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not disable_refs and self._ref_resolver_factory is None:
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.error('ReferenceResolver.Factory was never set in '
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      'APIDataSource.Factory.')
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return APIDataSource(self._permissions_cache,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self._json_cache,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self._idl_cache,
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self._json_cache_no_refs,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self._idl_cache_no_refs,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self._names_cache,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self._idl_names_cache,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           self._base_path,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           samples,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           disable_refs)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _LoadPermissions(self, json_str):
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return json.loads(json_comment_eater.Nom(json_str))
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _LoadJsonAPI(self, api, disable_refs):
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return _JSCModel(
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json.loads(json_comment_eater.Nom(api))[0],
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._ref_resolver_factory.Create() if not disable_refs else None,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disable_refs).ToDict()
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _LoadIdlAPI(self, api, disable_refs):
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      idl = idl_parser.IDLParser().ParseData(api)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return _JSCModel(
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          idl_schema.IDLSchema(idl).process()[0],
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._ref_resolver_factory.Create() if not disable_refs else None,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          disable_refs).ToDict()
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GetIDLNames(self, apis):
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        model.UnixName(os.path.splitext(api[len('%s/' % self._base_path):])[0])
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for api in apis if api.endswith('.idl')
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def _GetAllNames(self, apis):
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return [
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        model.UnixName(os.path.splitext(api[len('%s/' % self._base_path):])[0])
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for api in apis
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               permissions_cache,
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               json_cache,
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               idl_cache,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               json_cache_no_refs,
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               idl_cache_no_refs,
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               names_cache,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               idl_names_cache,
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               base_path,
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               samples,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               disable_refs):
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._base_path = base_path
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._permissions_cache = permissions_cache
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._json_cache = json_cache
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._idl_cache = idl_cache
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._json_cache_no_refs = json_cache_no_refs
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._idl_cache_no_refs = idl_cache_no_refs
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._names_cache = names_cache
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._idl_names_cache = idl_names_cache
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._samples = samples
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._disable_refs = disable_refs
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetPermsFromFile(self, filename):
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      perms = self._permissions_cache.GetFromFile('%s/%s' %
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (self._base_path, filename))
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return dict((model.UnixName(k), v) for k, v in perms.iteritems())
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except FileNotFoundError:
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return {}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetFeature(self, path):
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Remove 'experimental_' from path name to match the keys in
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # _permissions_features.json.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path = model.UnixName(path.replace('experimental_', ''))
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for filename in ['_permission_features.json', '_manifest_features.json']:
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      api_perms = self._GetPermsFromFile(filename).get(path, None)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if api_perms is not None:
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if api_perms and api_perms['channel'] in ('trunk', 'dev', 'beta'):
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      api_perms[api_perms['channel']] = True
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return api_perms
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateHandlebarContext(self, handlebar_dict, path):
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_dict = {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'permissions': self._GetFeature(path),
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'samples': _LazySamplesGetter(path, self._samples)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_dict.update(handlebar_dict)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return return_dict
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetAsSubdirectory(self, name):
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if name.startswith('experimental_'):
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parts = name[len('experimental_'):].split('_', 1)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parts[1] = 'experimental_%s' % parts[1]
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '/'.join(parts)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return name.replace('_', '/', 1)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def get(self, key):
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'):
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path, ext = os.path.splitext(key)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path = key
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unix_name = model.UnixName(path)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    names = self._names_cache.GetFromFileListing(self._base_path)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if unix_name not in names and self._GetAsSubdirectory(unix_name) in names:
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unix_name = self._GetAsSubdirectory(unix_name)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._disable_refs:
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache, ext = (
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (self._json_cache_no_refs, '.json'))
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    (self._json_cache, '.json'))
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._GenerateHandlebarContext(
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)),
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        path)
442