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

Side by Side Diff: chrome/common/extensions/docs/server2/availability_data_source.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: Revisions, Offline/Online Access (bypassed-hooks) Created 7 years, 7 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 os
7
8 from branch_utility import BranchUtility
9 from chrome_version_utility import ChromeVersionUtility
10 from file_system import FileNotFoundError
11 import svn_constants
12 from third_party.json_schema_compiler import json_parse, model
13
14 EXTENSION_API = 'extension_api.json'
15 MANIFEST_FEATURES = '_manifest_features.json'
16 PERMISSION_FEATURES = '_permission_features.json'
17
18 class AvailabilityDataSource(object):
not at google - send to devlin 2013/05/13 21:26:41 Late stage for this, but this isn't actually a *Da
epeterson 2013/05/15 07:38:34 Done.
19 '''Uses API data sources generated by a ChromeVersionDataSource in order to
20 search the filesystem for the earliest existence of a specified API throughout
21 the different versions of Chrome; this constitutes an API's availability.
22 '''
23 class Factory(object):
24 def __init__(self,
25 chrome_version_utility,
26 object_store_creator,
27 create_file_system):
not at google - send to devlin 2013/05/13 21:26:41 Can we try making this a method of ChromeVersionUt
28 self._chrome_version_utility = chrome_version_utility
29 self._object_store_creator = object_store_creator
30 self._create_file_system = create_file_system
31
32 def Create(self):
33 return AvailabilityDataSource(self._chrome_version_utility,
34 self._object_store_creator,
35 self._create_file_system)
36
37 def __init__(self,
38 chrome_version_utility,
39 object_store_creator,
40 create_file_system):
41 self._chrome_version_utility = chrome_version_utility
42 self._object_store_creator = object_store_creator
43 self._create_file_system = create_file_system
44
45 svn_file_system = create_file_system('trunk')
46 def read_json(path):
47 return json_parse.Parse(svn_file_system.ReadSingle(path))
48 self._existing_availabilities = read_json(
49 '%s/api_availabilities.json' % svn_constants.JSON_PATH)
50 self._permission_features = read_json(
51 '%s/%s' % (svn_constants.API_PATH, PERMISSION_FEATURES))
52 self._manifest_features = read_json(
53 '%s/%s' % (svn_constants.API_PATH, MANIFEST_FEATURES))
not at google - send to devlin 2013/05/13 15:43:32 here is one problem. The file systems are being re
not at google - send to devlin 2013/05/13 21:26:41 Continuing from this comment, and reading below: I
54
55 def create_object_store(category):
56 return (object_store_creator.Create(AvailabilityDataSource,
57 category=category))
58 self._permission_object_store = create_object_store('permission')
59 self._manifest_object_store = create_object_store('manifest')
60 self._names_object_store = create_object_store('names')
61 self._object_store = create_object_store(None)
62
63 self._permission_apis = []
64 self._manifest_apis = []
65 self._orphan_apis = []
not at google - send to devlin 2013/05/13 21:26:41 Looking at the way this is used, it's a bit strang
66
67 def _ReadJson(self, svn_file_system, path):
68 return json_parse.Parse(svn_file_system.ReadSingle(path))
69
70 def _GetChannelFromPermissionFeatures(self, api_name, permission_features):
not at google - send to devlin 2013/05/13 21:26:41 this function should be able to use self._permissi
epeterson 2013/05/15 07:38:34 Done.
71 '''Handles finding API channel information from _permission_features.json.
72 Sometimes this info will be in a dict, but other times it will be
73 in a dict contained in a list.
74 '''
75 channel = None
76 api_info = permission_features.get(api_name)
77 if api_info is not None:
78 if isinstance(api_info, collections.Mapping):
79 channel = api_info.get('channel')
80 else:
81 channel = BranchUtility.NewestChannel([entry.get('channel')
82 for entry in api_info])
not at google - send to devlin 2013/05/13 21:26:41 I don't think that the list comprehension is neces
epeterson 2013/05/15 07:38:34 Done.
83 return channel
84
85 def _CheckStablePermissionExistence(self, api_name, version):
86 '''Checks _permission_features.json for the given |version| of Chrome,
87 and returns a boolean representing whether or not the API was available on
88 the stable channel in |version|.
89 '''
90 existence = self._permission_object_store.Get(
91 '%s%s' % (api_name, version)).Get()
92 if existence is not None:
93 return existence
94 svn_file_system = self._create_file_system(
95 self._chrome_version_utility.GetBranchNumberForVersion(version))
96 permission_features = self._ReadJson(
97 svn_file_system,
98 '%s/%s' % (svn_constants.API_PATH, PERMISSION_FEATURES))
99 existence = 'stable' == self._GetChannelFromPermissionFeatures(
100 api_name,
101 permission_features)
102 self._object_store.Set('%s%s' % (api_name, version), existence)
103 return existence
104
105 def _CheckManifestExistence(self, api_name, version):
106 '''As a fallback measure for an API not being found in _permission_features,
107 check _manifest_features.json for the given |version| of Chrome,
108 and return a boolean representing whether or not the API was represented
109 within the file.
110 '''
111 #_manifest_features.json uses unix_hacker_style API names.
112 api_name = model.UnixName(api_name)
113 existence = self._manifest_object_store.Get(
114 '%s%s' % (api_name, version)).Get()
115 if existence is not None:
116 return existence
117 svn_file_system = self._create_file_system(
118 self._chrome_version_utility.GetBranchNumberForVersion(version))
119 manifest_features = self._ReadJson(
120 svn_file_system,
121 '%s/%s' % (svn_constants.API_PATH, MANIFEST_FEATURES))
122 if manifest_features.get(api_name) is not None:
123 existence = True
124 else:
125 existence = False
not at google - send to devlin 2013/05/13 21:26:41 existence = api_name in manifest_features
epeterson 2013/05/15 07:38:34 Done.
126 self._object_store.Set('%s%s' % (api_name, version), existence)
127 return existence
128
129 def _GetAllNames(self, files_dict):
130 '''Returns extension-less names for a list of files.
131 '''
132 files = files_dict[svn_constants.API_PATH + '/']
133 return [os.path.splitext(f)[0] for f in files]
134
135 def _CheckFileSystemExistence(self, api_name, version):
136 '''Uses a list of API names for a given branch to check simply for the
137 existence of a given API in that branch.
138 '''
139 names = self._names_object_store.Get(version).Get()
140 if names is not None:
141 return api_name in names
142 svn_file_system = self._create_file_system(
143 self._chrome_version_utility.GetBranchNumberForVersion(version))
144 names = svn_file_system.Read([svn_constants.API_PATH + '/']).Get()
not at google - send to devlin 2013/05/13 21:26:41 ReadSingle search in this file for ".Read(" and s
epeterson 2013/05/15 07:38:34 Done.
145 names = self._GetAllNames(names)
146 self._object_store.Set(version, names)
147 return api_name in names
148
149 def _CheckExtensionAPIExistence(self, api_name, version):
150 '''Parses the extension_api.json file (available in earlier versions of
151 chrome) for an API namespace. If this is successfully found, then the API
152 is considered to have been 'stable' for the given version.
153 '''
154 # The extension_api.json files only appear from version 5 to version 17.
155 if int(version) > 17 or int(version) < 5:
not at google - send to devlin 2013/05/13 21:26:41 make these assert, this method should only be call
epeterson 2013/05/15 07:38:34 Done.
156 return False
157
158 # Re-use this object-store - the versions won't conflict with each other.
159 existence = self._names_object_store.Get('%s%s' % (api_name, version)).Get()
not at google - send to devlin 2013/05/13 21:26:41 I don't think caching needs to be done here, you'r
epeterson 2013/05/15 07:38:34 Done.
160 if existence is not None:
161 return existence
162 svn_file_system = self._create_file_system(
163 self._chrome_version_utility.GetBranchNumberForVersion(version))
164 try:
165 extension_api = self._ReadJson(
166 svn_file_system,
167 '%s/%s' % (svn_constants.API_PATH, EXTENSION_API))
168 api_rows = [row.get('namespace') for row in extension_api
169 if 'namespace' in row]
170 return True if api_name in api_rows else False
171 except FileNotFoundError as e:
172 # This should only happen on preview.py, since extension_api.json is no
173 # longer present in current versions.
174 return False
175
176 def _FindEarliestStableAvailability(self, api_name, version):
177 '''Searches in descending order through filesystem caches tied to specific
178 chrome version numbers and looks for the availability of an API, |api_name|,
179 on the stable channel. When a version is found where the API is no longer
180 available on stable, returns the previous version number (the last known
181 version where the API was stable).
182 '''
183 # The _permission_features.json file (with 'channel' keys) is present only
184 # in Chrome 20 and onwards. We'll also check the _manifest_features.json if
185 # an API isn't found in _permission_features, and, failing that, we'll check
186 # for the API's existence in the filesystem.
187 while version >= 20:
188 if ((api_name in self._permission_apis
189 and self._CheckStablePermissionExistence(api_name, str(version)))
190 or (api_name in self._manifest_apis
191 and self._CheckManifestExistence(api_name, str(version)))
192 or (api_name in self._orphan_apis
193 and self._CheckFileSystemExistence(api_name, str(version)))):
194 version -= 1
195 else:
196 break
not at google - send to devlin 2013/05/13 21:26:41 THis method is super cool, but a bit odd to read a
epeterson 2013/05/15 07:38:34 Done.
197 # These versions are a little troublesome. Version 19 has
198 # _permission_features.json, but it lacks 'channel' information. Version 18
199 # doesn't have either of the json files. For now, we're using a simple check
200 # for filesystem existence here.
201 while version < 20 and version >= 18:
202 if self._CheckFileSystemExistence(api_name, str(version)):
203 version -= 1
204 else:
205 break
206 # Versions 17 and earlier have an extension_api.json file which contains
207 # namespaces for each API that was available at the time. We can use this
208 # file to check for existence, however, we no longer have
209 # file system access after version 5, so stop there.
210 while version < 18 and version >= 5:
211 if self._CheckExtensionAPIExistence(api_name, str(version)):
not at google - send to devlin 2013/05/13 21:26:41 why str(version)? Can we use ints everywhere?
epeterson 2013/05/15 07:38:34 Done.
212 version -= 1
213 else:
214 break
215 return str(version + 1)
216
217 def GetAvailability(self, api_name):
not at google - send to devlin 2013/05/13 21:26:41 I will want to add event/function/property availab
epeterson 2013/05/15 07:38:34 Done.
218 '''Determines the availability for an API by testing several scenarios.
219 (i.e. Is the API experimental? Only available on certain development
220 channels? If it's stable, when did it first become stable? etc.)
221 '''
222 availability = self._object_store.Get(api_name).Get()
223 if availability is not None:
224 return availability
225
226 # Check for a predetermined availability for this API.
227 availability = self._existing_availabilities.get(api_name)
not at google - send to devlin 2013/05/13 21:26:41 e.g. in lazy creation world this would be self._Ge
epeterson 2013/05/15 07:38:34 Done.
228 if availability is not None:
229 self._object_store.Set(api_name, availability)
230 return availability
231
232 latest_version = str(self._chrome_version_utility.GetLatestVersionNumber())
233 channel = self._GetChannelFromPermissionFeatures(api_name,
234 self._permission_features)
not at google - send to devlin 2013/05/13 21:26:41 This won't actually work properly, though: say if
epeterson 2013/05/15 07:38:34 So this is a bit of a mess now. Couldn't quite get
235
236 # There are three different scenarios for APIs in Chrome 20 and up. They
237 # can be in _permission_features, _manifest_features, or neither of the two.
238 # APIs are added to a respective list depending on which of these scenarios
239 # they fall into within the trunk filesystem.
240 if channel is not None:
241 # This is a special case: availability can be any of the dev channels.
242 # First, check for this case before checking for stable existence.
243 availability = channel
244 self._permission_apis.append(api_name)
245 elif self._CheckManifestExistence(api_name, latest_version):
246 availability = 'stable'
247 self._manifest_apis.append(api_name)
248 elif self._CheckFileSystemExistence(api_name, latest_version):
249 availability = 'stable'
250 self._orphan_apis.append(api_name)
251 else:
252 raise FileNotFoundError(
253 'The API schema for %s could not be located.' % api_name)
254 availability = None
255
256 if availability == 'stable':
257 availability = self._FindEarliestStableAvailability(
258 api_name,
259 int(latest_version) - 1)
260 self._object_store.Set(api_name, availability)
261 return availability
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698