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

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

Issue 12996003: Dynamically generate a heading for Extension Docs API pages (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: AvailabilityFinder Overhaul; Removing ConfigureFakeFetchers() calls Created 7 years, 6 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
OLDNEW
(Empty)
1 # Copyright (c) 2013 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
5 import collections
6 import logging
7 import os
8
9 from branch_utility import BranchUtility
10 from compiled_file_system import CompiledFileSystem
11 from file_system import FileNotFoundError
12 import svn_constants
13 from third_party.json_schema_compiler import json_parse, model
14
15 _API_AVAILABILITIES = svn_constants.JSON_PATH + '/api_availabilities.json'
16 _EXTENSION_API = svn_constants.API_PATH + '/extension_api.json'
17 _API_FEATURES = svn_constants.API_PATH + '/_api_features.json'
18 _MANIFEST_FEATURES = svn_constants.API_PATH + '/_manifest_features.json'
19 _PERMISSION_FEATURES = svn_constants.API_PATH + '/_permission_features.json'
20
21 def _GetChannelFromFeature(feature):
22 '''Handles finding API channel information from _features.json files.
not at google - send to devlin 2013/06/05 00:24:09 "Finds API channel information..."
epeterson 2013/06/17 20:05:49 Done.
23 Sometimes this info will be in a dict, but other times it will be
24 in a dict contained in a list for whitelisting purposes.
25 '''
26 channel = None
27 if feature is not None:
28 if isinstance(feature, collections.Mapping):
29 channel = feature.get('channel')
30 else:
31 channel = BranchUtility.NewestChannel(entry.get('channel')
32 for entry in feature)
33 return channel
not at google - send to devlin 2013/06/05 00:24:09 more concise: if feature is None: return None i
epeterson 2013/06/17 20:05:49 Done.
34
epeterson 2013/06/02 00:25:50 A lot of the logic for checking individual files/f
35 def _GetFeature(api_name, file_system, path, unix_name=False):
not at google - send to devlin 2013/06/05 00:24:09 this is only used in ExistsInFeatures, move it in
epeterson 2013/06/17 20:05:49 Done. It might be useful to access the rest of the
36 '''Gets the data for a given API schema from api/_api_features.json
37 within the given file system.
38 '''
39 if unix_name:
40 api_name = model.UnixName(api_name)
not at google - send to devlin 2013/06/05 00:24:09 what is this unix_name thing?
epeterson 2013/06/17 20:05:49 _manifest_features.json uses unix_style API names,
41 return file_system.GetFromFile(path).get(api_name)
42
43 def _ExistsInFeatures(api_name, file_system, path, unix_name=False):
not at google - send to devlin 2013/06/05 00:24:09 as per comment way below, call all of these method
epeterson 2013/06/17 20:05:49 Done.
44 '''Returns the name of the development channel that the API is available on
45 if this information can be located in the _features.json file specified by
46 |path| within the given |file_system|. Returns None, otherwise.
47 '''
48 return _GetChannelFromFeature(
49 _GetFeature(api_name, file_system, path, unix_name))
50
51 def _ExistsInApiFeatures(api_name, file_system):
52 try:
53 return _ExistsInFeatures(api_name, file_system, _API_FEATURES)
54 except FileNotFoundError as e:
55 # TODO(epeterson) Remove except block once _api_features is in all channels.
56 logging.warning('_api_features.json not found')
not at google - send to devlin 2013/06/05 00:24:09 don't warn it'll pollute the logs - but good point
epeterson 2013/06/17 20:05:49 Done.
57 return False
58
59 def _ExistsInPermissionFeatures(api_name, file_system):
60 return _ExistsInFeatures(api_name, file_system, _PERMISSION_FEATURES)
61
62 def _ExistsInManifestFeatures(api_name, file_system):
not at google - send to devlin 2013/06/05 00:24:09 _GetChannelFromManifestFeatures
epeterson 2013/06/17 20:05:49 Done.
63 return _ExistsInFeatures(api_name, file_system, _MANIFEST_FEATURES)
64
65 def _ExistsInFileSystem(api_name, file_system):
66 '''Checks for existence of |api_name| within the list of files in the api/
67 directory found using the given file system.
68 '''
69 api_name = model.UnixName(api_name)
70 return api_name in file_system.GetFromFileListing(svn_constants.API_PATH)
71
72 def _ExistsInExtensionApi(api_name, file_system):
73 '''Parses the api/extension_api.json file (available in Chrome versions
74 before 18) for an API namespace. If this is successfully found, then the API
75 is considered to have been 'stable' for the given version.
76 '''
77 try:
78 extension_api_json = file_system.GetFromFile(_EXTENSION_API)
79 api_rows = [row.get('namespace') for row in extension_api_json
80 if 'namespace' in row]
81 return True if api_name in api_rows else False
82 except FileNotFoundError as e:
83 # This should only happen on preview.py since extension_api.json is no
84 # longer present in trunk.
85 return False
86
87 class AvailabilityFinder(object):
88 '''Uses API data sources generated by a ChromeVersionDataSource in order to
89 search the filesystem for the earliest existence of a specified API throughout
90 the different versions of Chrome; this constitutes an API's availability.
91 '''
92 class Factory(object):
93 def __init__(self,
94 object_store_creator,
95 compiled_host_fs_factory,
96 branch_utility,
97 create_file_system):
not at google - send to devlin 2013/06/05 00:24:09 please document create_file_system. create_file_sy
epeterson 2013/06/17 20:05:49 Done.
98 self._object_store_creator = object_store_creator
99 self._compiled_host_fs_factory = compiled_host_fs_factory
100 self._branch_utility = branch_utility
101 self._create_file_system = create_file_system
102
103 def Create(self):
104 return AvailabilityFinder(self._object_store_creator,
105 self._compiled_host_fs_factory,
106 self._branch_utility,
107 self._create_file_system)
108
109 def __init__(self,
110 object_store_creator,
111 compiled_host_fs_factory,
112 branch_utility,
113 create_file_system):
114 self._object_store_creator = object_store_creator
115 self._json_cache = compiled_host_fs_factory.Create(
116 lambda _, json: json_parse.Parse(json),
117 AvailabilityFinder,
118 'json-cache')
119 self._branch_utility = branch_utility
120 self._create_file_system = create_file_system
121 self._object_store = object_store_creator.Create(AvailabilityFinder)
122
123 def _CreateFeaturesAndNamesFileSystems(self, version):
epeterson 2013/06/02 00:25:50 Checking _features.json files requires a different
124 '''The 'features' compiled file system's populate function parses and
125 returns the contents of a _features.json file. The 'names' compiled file
126 system's populate function creates a list of file names with .json or .idl
127 extensions.
128 '''
129 fs_factory = CompiledFileSystem.Factory(
not at google - send to devlin 2013/06/05 00:24:09 recreating them each time like this is inefficent
epeterson 2013/06/17 20:05:49 Done.
130 self._create_file_system(version),
131 self._object_store_creator)
132 features_fs = fs_factory.Create(lambda _, json: json_parse.Parse(json),
133 AvailabilityFinder,
134 '%sFeatures' % version)
not at google - send to devlin 2013/06/05 00:24:09 category= also you don't need the version since t
epeterson 2013/06/17 20:05:49 Ok, this clears things up. thank you.
135 names_fs = fs_factory.Create(self._GetExtNames,
136 AvailabilityFinder,
137 '%sNames' % version)
not at google - send to devlin 2013/06/05 00:24:09 likewise category='names'
epeterson 2013/06/17 20:05:49 Done.
138 return (features_fs, names_fs)
139
140 def _GetExtNames(self, base_path, apis):
141 return [os.path.splitext(api)[0] for api in apis
142 if os.path.splitext(api)[1][1:] in ['json', 'idl']]
143
144 def _FindEarliestAvailability(self, api_name, version):
145 '''Searches in descending order through filesystem caches tied to specific
146 chrome version numbers and looks for the availability of an API, |api_name|,
147 on the stable channel. When a version is found where the API is no longer
148 available on stable, returns the previous version number (the last known
149 version where the API was stable).
150 '''
epeterson 2013/06/02 00:25:50 I think this code looks a lot more readable, and s
not at google - send to devlin 2013/06/05 00:24:09 Yes much better, though recursiveness should be av
epeterson 2013/06/17 20:05:49 Here's an iterative version.
151 if version >= 5:
152 features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version)
not at google - send to devlin 2013/06/05 00:24:09 just have an "if version < 5: return version" at t
epeterson 2013/06/17 20:05:49 Done.
153
154 available = False
155 # The _api_features.json file first appears in version 28 and should be the
156 # most reliable for finding API availabilities, so it gets checked first.
157 # The _permission_features.json and _manifest_features.json files are
158 # present in Chrome 20 and onwards. Fall back to a check for file system
159 # existence if the API is not stable in any of the _features.json files.
not at google - send to devlin 2013/06/05 00:24:09 could you put all of these comments inside the blo
epeterson 2013/06/17 20:05:49 Done.
160 if version >= 28:
161 available = _ExistsInApiFeatures(api_name, features_fs) == 'stable'
162 # Check other _features.json files/file existence if the API wasn't found in
163 # _api_features.json, or if _api_features.json wasn't present.
164 if version >= 20:
165 available = available or (
166 _ExistsInPermissionFeatures(api_name, features_fs) == 'stable'
167 or _ExistsInManifestFeatures(api_name, features_fs) == 'stable'
168 or _ExistsInFileSystem(api_name, names_fs))
169 # These versions are a little troublesome. Version 19 has
170 # _permission_features.json, but it lacks 'channel' information. Version 18
171 # lacks all of the _features.json files. For now, we're using a simple check
172 # for filesystem existence here.
173 elif version >= 18:
174 available = _ExistsInFileSystem(api_name, names_fs)
175 # Versions 17 and down to 5 have an extension_api.json file which contains
176 # namespaces for each API that was available at the time. We can use this
177 # file to check for API existence.
178 elif version >= 5:
179 available = _ExistsInExtensionApi(api_name, features_fs)
180
181 if available:
182 return self._FindEarliestAvailability(api_name, version - 1)
183 return version + 1
184
185 def _IsAvailableInFileSystem(self, api_name, version):
not at google - send to devlin 2013/06/05 00:24:09 as noted below, make this _GetAvailableChannelForV
epeterson 2013/06/17 20:05:49 Done.
186 features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version)
187 return (_ExistsInApiFeatures(api_name, features_fs)
188 or _ExistsInPermissionFeatures(api_name, features_fs)
189 or _ExistsInManifestFeatures(api_name, features_fs)
190 or _ExistsInFileSystem(api_name, names_fs))
191
192 def GetApiAvailability(self, api_name):
193 '''Determines the availability for an API by testing several scenarios.
194 (i.e. Is the API experimental? Only available on certain development
195 channels? If it's stable, when did it first become stable? etc.)
196 '''
197 availability = self._object_store.Get(api_name).Get()
198 if availability is not None:
199 return availability
200
201 # Check for a predetermined availability for this API.
202 api_info = self._json_cache.GetFromFile(_API_AVAILABILITIES).get(api_name)
203 if api_info is not None:
204 channel = api_info.get('channel')
205 version = api_info.get('version') if channel == 'stable' else None
206 availability = AvailabilityInfo(channel, version)
207 self._object_store.Set(api_name, availability)
208 return availability
not at google - send to devlin 2013/06/05 00:24:09 more concise: availability = AvailabilityInfo(api
epeterson 2013/06/17 20:05:49 Done.
209
210 # Check for the API in the development channels.
211 availability = None
212 for channel_info in self._branch_utility.GetAllChannelInfo():
213 if self._IsAvailableInFileSystem(api_name,
214 channel_info.version):
215 availability = AvailabilityInfo(channel_info.channel,
216 channel_info.version)
217 break
not at google - send to devlin 2013/06/05 00:24:09 i think this has a bug in scenarios such as: an AP
epeterson 2013/06/17 20:05:49 Going to continue testing as I prepare to submit a
218
219 # The API should at least be available on trunk. It's a bug otherwise.
220 assert availability, 'No availability found for %s' % api_name
221
222 # If the API is in stable, find the chrome version in which it became
223 # stable.
224 if availability.channel == 'stable':
225 availability.version = self._FindEarliestAvailability(
226 api_name,
227 availability.version)
228
229 self._object_store.Set(api_name, availability)
230 return availability
231
232 class AvailabilityInfo(object):
not at google - send to devlin 2013/06/05 00:24:09 declare at top
epeterson 2013/06/17 20:05:49 Done.
233 def __init__(self, channel, version):
234 self.channel = channel
235 self.version = version
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698