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

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: Finding earliest 'stable' availability using features files 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 json
6 import logging
7 import os
8
9 from appengine_url_fetcher import AppEngineUrlFetcher
10 from caching_file_system import CachingFileSystem
11 from compiled_file_system import CompiledFileSystem
12 from subversion_file_system import SubversionFileSystem
13 import svn_constants
14 from third_party.json_schema_compiler import json_comment_eater
15 from third_party.json_schema_compiler import model
16 import url_constants
17
18 # These labels are used for interacting with AvailabilityDataSource's object
19 # store. The format is <label><string> (e.g. svn21, or permissiontabs26)
20 SVN = 'svn'
21 PERMISSION = 'permission'
22 MANIFEST = 'manifest'
23 FILESYS = 'filesys'
not at google - send to devlin 2013/04/27 01:48:34 this is what the category= parameter to ObjectStor
24
25 class AvailabilityDataSource(object):
26 '''Uses API data sources generated by a ChromeVersionDataSource in order to
27 search the filesystem for the earliest existence of a specified API throughout
28 the different versions of Chrome; this constitutes an API's availability.
29 '''
30 class Factory(object):
31 def __init__(self,
32 chrome_version_utility,
33 object_store_creator_factory,
34 svn_file_system):
35 self._chrome_version_utility = chrome_version_utility
36 self._object_store_creator_factory = object_store_creator_factory
37 json_string = svn_file_system.ReadSingle('%s/api_availabilities.json'
38 % svn_constants.JSON_PATH)
39 self._existing_availabilities = json.loads(json_string)
40 json_string = svn_file_system.ReadSingle('%s/_permission_features.json'
41 % svn_constants.API_PATH)
42 self._permission_features = json.loads(json_comment_eater.Nom(
43 json_string))
44 json_string = svn_file_system.ReadSingle('%s/_manifest_features.json'
45 % svn_constants.API_PATH)
46 self._manifest_features = json.loads(json_comment_eater.Nom(json_string))
47
48 def Create(self):
49 return AvailabilityDataSource(self._chrome_version_utility,
50 self._object_store_creator_factory,
51 self._existing_availabilities,
52 self._permission_features,
53 self._manifest_features)
54
55 def __init__(self,
56 chrome_version_utility,
57 object_store_creator_factory,
58 existing_availabilities,
59 permission_features,
60 manifest_features):
61 self._chrome_version_utility = chrome_version_utility
62 self._object_store_creator_factory = object_store_creator_factory
63 self._object_store = self._object_store_creator_factory.Create(
64 AvailabilityDataSource).Create()
65 self._existing_availabilities = existing_availabilities
66 self._permission_features = permission_features
67 self._manifest_features = manifest_features
68 self._permission_apis = []
69 self._manifest_apis = []
70 self._orphan_apis = []
71
72 def _CreateSvnFileSystemForBranch(self, branch):
73 '''Creates a file system tied to a specific |branch| of the svn repository.
74 '''
75 if branch == 'trunk':
76 svn_url = '/'.join((url_constants.SVN_TRUNK_URL,
77 'src',
78 svn_constants.EXTENSIONS_PATH))
79 else:
80 svn_url = '/'.join((url_constants.SVN_BRANCH_URL,
81 branch,
82 'src',
83 svn_constants.EXTENSIONS_PATH))
84 viewvc_url = svn_url.replace(url_constants.SVN_URL,
85 url_constants.VIEWVC_URL)
86
87 svn_file_system = CachingFileSystem(
88 SubversionFileSystem(AppEngineUrlFetcher(svn_url),
89 AppEngineUrlFetcher(viewvc_url)),
90 self._object_store_creator_factory)
not at google - send to devlin 2013/04/27 01:48:34 so this is obviously the same as server instance's
91 return svn_file_system
92
93 def _GetChannelFromPermissionFeatures(self, api_name, permission_features):
94 '''Sometimes the API information will be in a dict, other times it will be
95 in a dict contained in a list.
96 '''
97 api_info = permission_features.get(api_name, None)
98 if api_info is not None:
99 try:
100 channel = api_info.get('channel')
101 except AttributeError:
102 channel = api_info[0].get('channel')
103 finally:
104 return channel
105 return None
106
107 def _CheckStablePermissionExistence(self, api_name, version):
108 '''Checks _permission_features.json for the given |version| of Chrome,
109 and returns a boolean representing whether or not the API was available on
110 the stable channel in |version|.
111 '''
112 existence = self._object_store.Get('%s%s%s'
113 % (PERMISSION, api_name, version)).Get()
114 if existence is not None:
115 return existence
116
117 svn_file_system = self._object_store.Get('%s%s' % (SVN, version)).Get()
118 if svn_file_system is None:
119 svn_file_system = self._CreateSvnFileSystemForBranch(
120 self._chrome_version_utility.GetBranchNumberForVersion(version))
121 self._object_store.Set('%s%s' % (SVN, version), svn_file_system)
122
123 json_string = svn_file_system.ReadSingle('%s/_permission_features.json'
124 % svn_constants.API_PATH)
125 permission_features = json.loads(json_comment_eater.Nom(json_string))
126
127 existence = 'stable' == self._GetChannelFromPermissionFeatures(
128 api_name, permission_features)
129 self._object_store.Set('%s%s%s' % (PERMISSION, api_name, version),
130 existence)
131 return existence
132
133 def _CheckManifestExistence(self, api_name, version):
134 '''As a fallback measure for an API not being found in _permission_features,
135 check _manifest_features.json for the given |version| of Chrome,
136 and return a boolean representing whether or not the API was represented
137 within the file.
138 '''
139 #_manifest_features.json uses unix_hacker_style API names.
140 api_name = model.UnixName(api_name)
141 existence = self._object_store.Get('%s%s%s'
142 % (MANIFEST, api_name, version)).Get()
143 if existence is not None:
144 return existence
145
146 svn_file_system = self._object_store.Get('%s%s' % (SVN, version)).Get()
147 if svn_file_system is None:
148 svn_file_system = self._CreateSvnFileSystemForBranch(
149 self._chrome_version_utility.GetBranchNumberForVersion(version))
150 self._object_store.Set('%s%s' % (SVN, version), svn_file_system)
151
152 json_string = svn_file_system.ReadSingle('%s/_manifest_features.json'
153 % svn_constants.API_PATH)
154 manifest_features = json.loads(json_comment_eater.Nom(json_string))
155 if manifest_features.get(api_name, None) is not None:
156 existence = True
157 else:
158 existence = False
159 self._object_store.Set('%s%s%s' % (MANIFEST, api_name, version), existence)
160 return existence
161
162 def _GetAllNames(self, files_dict):
163 '''Returns extension-less names for a list of files.
164 '''
165 files = files_dict[svn_constants.API_PATH + '/']
166 return [model.UnixName(os.path.splitext(f)[0]) for f in files]
167
168 def _CheckFileSystemExistence(self, api_name, version):
169 '''Uses a list of API names for a given branch to check simply for the
170 existence of a given API in that branch.
171 '''
172 names = self._object_store.Get('%s%s' % (FILESYS, version)).Get()
173 if names is not None:
174 return api_name in names
175
176 svn_file_system = self._object_store.Get('%s%s' % (SVN, version)).Get()
177 if svn_file_system is None:
178 svn_file_system = self._CreateSvnFileSystemForBranch(
179 self._chrome_version_utility.GetBranchNumberForVersion(version))
180 self._object_store.Set('%s%s' % (SVN, version), svn_file_system)
181 names = svn_file_system.Read([svn_constants.API_PATH + '/']).Get()
182 names = self._GetAllNames(names)
183 self._object_store.Set('%s%s' % (FILESYS, version), names)
184 return api_name in names
185
186 def _FindEarliestStableAvailability(self, api_name, version):
187 '''Searches in descending order through filesystem caches tied to specific
188 chrome version numbers and looks for the availability of an API, |api_name|,
189 on the stable channel. When a version is found where the API is no longer
190 available on stable, returns the previous version number (the last known
191 version where the API was stable).
192 '''
193 # The _permission_features.json file (with 'channel' keys) is present only
194 # in Chrome 20 and onwards.
195 while version >= 20:
196 if ((api_name in self._permission_apis
197 and self._CheckStablePermissionExistence(api_name, str(version)))
198 or (api_name in self._manifest_apis
199 and self._CheckManifestExistence(api_name, str(version)))
200 or (api_name in self._orphan_apis
201 and self._CheckFileSystemExistence(api_name, str(version)))):
202 version -= 1
203 else:
204 break
205 version += 1
206 return str(version)
207
208 def GetAvailability(self, api_name):
209 '''Determines the availability for an API by testing several scenarios.
210 (i.e. Is the API experimental? Only available on certain development
211 channels? If it's stable, when did it first become stable? etc.)
212 '''
213 availability = self._object_store.Get(api_name).Get()
214 if availability is not None:
215 return availability
216
217 # Check for a predetermined availability for this API.
218 availability = self._existing_availabilities.get(api_name, None)
219 if availability is not None:
220 self._object_store.Set(api_name, availability)
221 return availability
222
223 latest_version = str(self._chrome_version_utility.GetLatestVersionNumber())
224 channel = self._GetChannelFromPermissionFeatures(api_name,
225 self._permission_features)
226 if channel is not None:
227 # This is a special case: availability can be any of the dev channels,
228 # to check for this information instead of checking just for existence.
229 availability = channel
230 self._permission_apis.append(api_name)
231 elif self._CheckManifestExistence(api_name, latest_version):
232 availability = 'stable'
233 self._manifest_apis.append(api_name)
234 elif self._CheckFileSystemExistence(api_name, latest_version):
235 availability = 'stable'
236 self._orphan_apis.append(api_name)
237 else:
238 logging.warning('%s could not be located. %s\'s availability is None.'
239 % (api_name, api_name))
240 availability = None
241
242 if availability != 'stable':
243 self._object_store.Set(api_name, availability)
244 return availability
245
246 availability = self._FindEarliestStableAvailability(api_name,
247 int(latest_version) - 1)
248 self._object_store.Set(api_name, availability)
249 return availability
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698