Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(978)

Side by Side Diff: chrome/common/extensions/docs/server2/availability_finder.py

Issue 25627002: Docserver: when checking for the existence of an API on a branch, just look at (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: jeffrey Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 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 collections 5 from collections import Mapping
6 import os 6 import os
7 7
8 from api_schema_graph import APISchemaGraph 8 from api_schema_graph import APISchemaGraph
9 from branch_utility import BranchUtility 9 from branch_utility import BranchUtility
10 from compiled_file_system import CompiledFileSystem 10 from compiled_file_system import CompiledFileSystem
11 from svn_constants import API_PATH 11 from svn_constants import API_PATH
12 from third_party.json_schema_compiler import idl_schema, idl_parser, json_parse 12 from third_party.json_schema_compiler import idl_schema, idl_parser, json_parse
13 from third_party.json_schema_compiler.json_parse import OrderedDict 13 from third_party.json_schema_compiler.json_parse import OrderedDict
14 from third_party.json_schema_compiler.model import UnixName 14 from third_party.json_schema_compiler.model import UnixName
15 15
16 16
17 _EXTENSION_API = 'extension_api.json' 17 _EXTENSION_API = 'extension_api.json'
18 18
19 19
20 def _GetChannelFromFeatures(api_name, file_system, path): 20 def _GetChannelFromFeatures(api_name, file_system, path):
21 '''Finds API channel information within _features.json files at the given 21 '''Finds API channel information within _features.json files at the given
22 |path| for the given |file_system|. Returns None if channel information for 22 |path| for the given |file_system|. Returns None if channel information for
23 the API cannot be located. 23 the API cannot be located.
24 ''' 24 '''
25 feature = file_system.GetFromFile(path).get(api_name) 25 feature = file_system.GetFromFile(path).get(api_name)
26 26
27 if feature is None: 27 if feature is None:
28 return None 28 return None
29 if isinstance(feature, collections.Mapping): 29 if isinstance(feature, Mapping):
30 # The channel information exists as a solitary dict. 30 # The channel information exists as a solitary dict.
31 return feature.get('channel') 31 return feature.get('channel')
32 # The channel information dict is nested within a list for whitelisting 32 # The channel information dict is nested within a list for whitelisting
33 # purposes. Take the newest channel out of all of the entries. 33 # purposes. Take the newest channel out of all of the entries.
34 return BranchUtility.NewestChannel(entry.get('channel') for entry in feature) 34 return BranchUtility.NewestChannel(entry.get('channel') for entry in feature)
35 35
36 36
37 def _GetChannelFromApiFeatures(api_name, file_system): 37 def _GetChannelFromApiFeatures(api_name, file_system):
38 return _GetChannelFromFeatures( 38 return _GetChannelFromFeatures(
39 api_name, 39 api_name,
40 file_system, 40 file_system,
41 '%s/_api_features.json' % API_PATH) 41 '%s/_api_features.json' % API_PATH)
42 42
43 43
44 def _GetChannelFromManifestFeatures(api_name, file_system): 44 def _GetChannelFromManifestFeatures(api_name, file_system):
45 return _GetChannelFromFeatures( 45 return _GetChannelFromFeatures(
46 UnixName(api_name), #_manifest_features uses unix_style API names 46 UnixName(api_name), #_manifest_features uses unix_style API names
47 file_system, 47 file_system,
48 '%s/_manifest_features.json' % API_PATH) 48 '%s/_manifest_features.json' % API_PATH)
49 49
50 50
51 def _GetChannelFromPermissionFeatures(api_name, file_system): 51 def _GetChannelFromPermissionFeatures(api_name, file_system):
52 return _GetChannelFromFeatures( 52 return _GetChannelFromFeatures(
53 api_name, 53 api_name,
54 file_system, 54 file_system,
55 '%s/_permission_features.json' % API_PATH) 55 '%s/_permission_features.json' % API_PATH)
56 56
57 57
58 def _GetApiSchemaFilename(api_name, file_system):
59 '''Gets the name of the file which contains the schema for |api_name| in
60 |file_system|, or None if the API is not found. Note that this may be the
61 single _EXTENSION_API file which all APIs share in older versions of Chrome.
62 '''
63 def under_api_path(path):
64 return '%s/%s' % (API_PATH, path)
65
66 file_names = file_system.ReadSingle(under_api_path(''))
67
68 if _EXTENSION_API in file_names:
69 # Prior to Chrome version 18, extension_api.json contained all API schema
70 # data, which replaced the current implementation of individual API files.
71 # We're forced to parse this (very large) file to determine if the API
72 # exists in it.
73 #
74 # TODO(epeterson) Avoid doing unnecessary work by re-parsing.
75 # See http://crbug.com/295812.
76 extension_api_json = json_parse.Parse(
77 file_system.ReadSingle('%s/%s'% (API_PATH, _EXTENSION_API)))
78 if any(api['namespace'] == api_name for api in extension_api_json):
79 return under_api_path(_EXTENSION_API)
80 return None
81
82 api_file_names = [
83 file_name for file_name in file_names
84 if os.path.splitext(file_name)[0] in (api_name, UnixName(api_name))]
85 assert len(api_file_names) < 2
86 return under_api_path(api_file_names[0]) if api_file_names else None
87
88
89 def _HasApiSchema(api_name, file_system):
90 return _GetApiSchemaFilename(api_name, file_system) is not None
91
92
58 def _GetApiSchema(api_name, file_system): 93 def _GetApiSchema(api_name, file_system):
59 '''Searches |file_system| for |api_name|'s API schema data, and parses and 94 '''Searches |file_system| for |api_name|'s API schema data, and parses and
60 returns it if found. 95 returns it if found.
61 ''' 96 '''
62 file_names = file_system.ReadSingle('%s/' % API_PATH) 97 api_file_name = _GetApiSchemaFilename(api_name, file_system)
63 # API names can be represented in unix_style and camelCase formats. 98 if api_file_name is None:
64 possibilities = (api_name, UnixName(api_name)) 99 return None
65 100
66 def get_file_data(file_name): 101 api_file_text = file_system.ReadSingle(api_file_name)
67 return file_system.ReadSingle('%s/%s' % (API_PATH, file_name)) 102 if api_file_name == _EXTENSION_API:
68 103 matching_schemas = [api for api in json_parse.Parse(api_file_text)
69 if _EXTENSION_API in file_names: 104 if api['namespace'] == api_name]
70 # Prior to Chrome version 18, extension_api.json contained all API schema 105 elif api_file_name.endswith('.idl'):
71 # data, which replaced the current implementation of individual API files. 106 matching_schemas = idl_parser.IDLParser().ParseData(api_file_text)
72 # 107 else:
73 # TODO(epeterson) This file will be parsed a lot, but the data remains the 108 matching_schemas = json_parse.Parse(api_file_text)
74 # same for each API. Avoid doing unnecessary work by re-parsing. 109 # There should only be a single matching schema per file.
75 # (see http://crbug.com/295812) 110 assert len(matching_schemas) == 1
76 extension_api_json = json_parse.Parse(get_file_data(_EXTENSION_API)) 111 return matching_schemas
77 api = [api for api in extension_api_json if api['namespace'] == api_name]
78 return api if api else None
79
80 def check_file(file_name):
81 return os.path.splitext(file_name)[0] in (api_name, UnixName(api_name))
82
83 for file_name in file_names:
84 if check_file(file_name):
85 if file_name.endswith('idl'):
86 idl_data = idl_parser.IDLParser().ParseData(get_file_data(file_name))
87 return idl_schema.IDLSchema(idl_data).process()
88 return json_parse.Parse(get_file_data(file_name))
89 return None
90 112
91 113
92 class AvailabilityFinder(object): 114 class AvailabilityFinder(object):
93 '''Generates availability information for APIs by looking at API schemas and 115 '''Generates availability information for APIs by looking at API schemas and
94 _features files over multiple release versions of Chrome. 116 _features files over multiple release versions of Chrome.
95 ''' 117 '''
96 118
97 def __init__(self, 119 def __init__(self,
98 file_system_iterator, 120 file_system_iterator,
99 object_store_creator, 121 object_store_creator,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 # found using _api_features.json. 154 # found using _api_features.json.
133 available_channel = available_channel or ( 155 available_channel = available_channel or (
134 _GetChannelFromPermissionFeatures(api_name, features_fs) 156 _GetChannelFromPermissionFeatures(api_name, features_fs)
135 or _GetChannelFromManifestFeatures(api_name, features_fs)) 157 or _GetChannelFromManifestFeatures(api_name, features_fs))
136 if available_channel is not None: 158 if available_channel is not None:
137 return available_channel == 'stable' 159 return available_channel == 'stable'
138 if version >= 5: 160 if version >= 5:
139 # Fall back to a check for file system existence if the API is not 161 # Fall back to a check for file system existence if the API is not
140 # stable in any of the _features.json files, or if the _features files 162 # stable in any of the _features.json files, or if the _features files
141 # do not exist (version 19 and earlier). 163 # do not exist (version 19 and earlier).
142 return _GetApiSchema(api_name, file_system) is not None 164 return _HasApiSchema(api_name, file_system)
143 165
144 def _CheckChannelAvailability(self, api_name, file_system, channel_name): 166 def _CheckChannelAvailability(self, api_name, file_system, channel_name):
145 '''Searches through the _features files in a given |file_system| and 167 '''Searches through the _features files in a given |file_system| and
146 determines whether or not an API is available on the given channel, 168 determines whether or not an API is available on the given channel,
147 |channel_name|. 169 |channel_name|.
148 ''' 170 '''
149 fs_factory = CompiledFileSystem.Factory(file_system, 171 fs_factory = CompiledFileSystem.Factory(file_system,
150 self._object_store_creator) 172 self._object_store_creator)
151 features_fs = fs_factory.Create(lambda _, json: json_parse.Parse(json), 173 features_fs = fs_factory.Create(lambda _, json: json_parse.Parse(json),
152 AvailabilityFinder, 174 AvailabilityFinder,
153 category='features') 175 category='features')
154 available_channel = (_GetChannelFromApiFeatures(api_name, features_fs) 176 available_channel = (_GetChannelFromApiFeatures(api_name, features_fs)
155 or _GetChannelFromPermissionFeatures(api_name, features_fs) 177 or _GetChannelFromPermissionFeatures(api_name, features_fs)
156 or _GetChannelFromManifestFeatures(api_name, features_fs)) 178 or _GetChannelFromManifestFeatures(api_name, features_fs))
157 if (available_channel is None and 179 if available_channel is None and _HasApiSchema(api_name, file_system):
158 _GetApiSchema(api_name, file_system) is not None):
159 # If an API is not represented in any of the _features files, but exists 180 # If an API is not represented in any of the _features files, but exists
160 # in the filesystem, then assume it is available in this version. 181 # in the filesystem, then assume it is available in this version.
161 # The windows API is an example of this. 182 # The windows API is an example of this.
162 available_channel = channel_name 183 available_channel = channel_name
163 # If the channel we're checking is the same as or newer than the 184 # If the channel we're checking is the same as or newer than the
164 # |available_channel| then the API is available at this channel. 185 # |available_channel| then the API is available at this channel.
165 return (available_channel is not None and 186 return (available_channel is not None and
166 BranchUtility.NewestChannel((available_channel, channel_name)) 187 BranchUtility.NewestChannel((available_channel, channel_name))
167 == channel_name) 188 == channel_name)
168 189
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 return availability 222 return availability
202 223
203 def GetApiNodeAvailability(self, api_name): 224 def GetApiNodeAvailability(self, api_name):
204 '''Returns an APISchemaGraph annotated with each node's availability (the 225 '''Returns an APISchemaGraph annotated with each node's availability (the
205 ChannelInfo at the oldest channel it's available in). 226 ChannelInfo at the oldest channel it's available in).
206 ''' 227 '''
207 availability_graph = self._node_level_object_store.Get(api_name).Get() 228 availability_graph = self._node_level_object_store.Get(api_name).Get()
208 if availability_graph is not None: 229 if availability_graph is not None:
209 return availability_graph 230 return availability_graph
210 231
232
211 availability_graph = APISchemaGraph() 233 availability_graph = APISchemaGraph()
212 trunk_graph = APISchemaGraph(_GetApiSchema(api_name, 234 trunk_graph = APISchemaGraph(_GetApiSchema(api_name,
213 self._host_file_system)) 235 self._host_file_system))
214 def update_availability_graph(file_system, channel_info): 236 def update_availability_graph(file_system, channel_info):
215 version_graph = APISchemaGraph(_GetApiSchema(api_name, file_system)) 237 version_graph = APISchemaGraph(_GetApiSchema(api_name, file_system))
216 # Keep track of any new schema elements from this version by adding 238 # Keep track of any new schema elements from this version by adding
217 # them to |availability_graph|. 239 # them to |availability_graph|.
218 # 240 #
219 # Calling |availability_graph|.Lookup() on the nodes being updated 241 # Calling |availability_graph|.Lookup() on the nodes being updated
220 # will return the |annotation| object. 242 # will return the |annotation| object.
221 availability_graph.Update(version_graph.Subtract(availability_graph), 243 availability_graph.Update(version_graph.Subtract(availability_graph),
222 annotation=channel_info) 244 annotation=channel_info)
223 245
224 # Continue looping until there are no longer differences between this 246 # Continue looping until there are no longer differences between this
225 # version and trunk. 247 # version and trunk.
226 return trunk_graph != version_graph 248 return trunk_graph != version_graph
227 249
228 self._file_system_iterator.Ascending( 250 self._file_system_iterator.Ascending(self.GetApiAvailability(api_name),
229 self.GetApiAvailability(api_name), 251 update_availability_graph)
230 update_availability_graph)
231 252
232 self._node_level_object_store.Set(api_name, availability_graph) 253 self._node_level_object_store.Set(api_name, availability_graph)
233 return availability_graph 254 return availability_graph
OLDNEW
« no previous file with comments | « chrome/common/extensions/docs/server2/app.yaml ('k') | chrome/common/extensions/docs/server2/branch_utility.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698