Index: chrome/common/extensions/docs/server2/availability_data_source.py |
diff --git a/chrome/common/extensions/docs/server2/availability_data_source.py b/chrome/common/extensions/docs/server2/availability_data_source.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4b63b90c297254c8f4917c78897e1bfd1e10f365 |
--- /dev/null |
+++ b/chrome/common/extensions/docs/server2/availability_data_source.py |
@@ -0,0 +1,142 @@ |
+# Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import json |
+import os |
+ |
+from appengine_url_fetcher import AppEngineUrlFetcher |
+from caching_file_system import CachingFileSystem |
+from compiled_file_system import CompiledFileSystem |
+from object_store_creator import ObjectStoreCreator |
+from subversion_file_system import SubversionFileSystem |
+import svn_constants |
+import third_party.json_schema_compiler.model as model |
+import url_constants |
+ |
epeterson
2013/04/17 03:38:50
Removed the [huge] dependency on api_data_source f
|
+class AvailabilityDataSource(object): |
+ '''Uses API data sources generated by a ChromeVersionDataSource in order to |
+ search the filesystem for the earliest existence of a specified API throughout |
+ the different versions of Chrome; this constitutes an API's availability. |
+ ''' |
+ class Factory(object): |
+ def __init__(self, chrome_version_utility, svn_file_system=None): |
+ self._chrome_version_utility = chrome_version_utility |
+ self._object_store = ObjectStoreCreator(AvailabilityDataSource).Create() |
+ |
+ # The |svn_file_system| will only be none for testing. |
+ if svn_file_system is not None: |
+ json_string = svn_file_system.ReadSingle('%s/api_availabilities.json' |
+ % svn_constants.JSON_PATH) |
+ self._existing_availabilities = json.loads(json_string) |
+ |
epeterson
2013/04/17 03:38:50
This hasn't been tested on the appengine, because
|
+ def Create(self): |
+ return AvailabilityDataSource(self._chrome_version_utility, |
+ self._object_store, |
+ self._existing_availabilities) |
+ |
+ def __init__(self, |
+ chrome_version_utility, |
+ object_store, |
+ existing_availabilities): |
+ self._chrome_version_utility = chrome_version_utility |
+ self._object_store = object_store |
+ self._existing_availabilities = existing_availabilities |
+ |
+ def _CreateSvnFileSystemForBranch(self, branch): |
+ '''Creates a file system tied to a a specific branch of the svn repository. |
+ ''' |
+ if branch == 'trunk': |
+ svn_url = '/'.join((url_constants.SVN_TRUNK_URL, |
+ 'src', |
+ svn_constants.EXTENSIONS_PATH)) |
+ else: |
+ svn_url = '/'.join((url_constants.SVN_BRANCH_URL, |
+ branch, |
+ 'src', |
+ svn_constants.EXTENSIONS_PATH)) |
+ viewvc_url = svn_url.replace(url_constants.SVN_URL, |
+ url_constants.VIEWVC_URL) |
+ |
+ svn_file_system = CachingFileSystem( |
+ SubversionFileSystem(AppEngineUrlFetcher(svn_url), |
+ AppEngineUrlFetcher(viewvc_url)), |
+ ObjectStoreCreator.Factory(branch)) |
+ return svn_file_system |
+ |
+ def _GetAllNames(self, base_dir, apis): |
+ '''Returns unix_hacker_style names for all APIs currently available. |
+ ''' |
+ return [ |
+ model.UnixName(os.path.splitext(api)[0]) |
+ for api in apis |
+ ] |
+ |
+ def _GetAsSubdirectory(self, name): |
+ if name.startswith('experimental_'): |
+ parts = name[len('experimental_'):].split('_', 1) |
+ if len(parts) > 1: |
+ parts[1] = 'experimental_%s' % parts[1] |
+ return '/'.join(parts) |
+ else: |
+ return '%s/%s' % (parts[0], name) |
+ return name.replace('_', '/', 1) |
+ |
+ def _CheckApiExistence(self, api_name, version): |
+ '''Finds a list of APIs that are present in the given |version|, and checks |
+ to see whether or not |api_name| exists in that list. |
+ ''' |
+ names = self._object_store.Get(version).Get() |
+ |
+ if names is None: |
+ svn_file_system = self._CreateSvnFileSystemForBranch( |
+ self._chrome_version_utility.GetBranchNumberForVersion(version)) |
+ compiled_fs_factory = CompiledFileSystem.Factory( |
+ svn_file_system, |
+ ObjectStoreCreator.Factory()) |
+ names_cache = compiled_fs_factory.Create(self._GetAllNames, |
+ AvailabilityDataSource) |
+ names = names_cache.GetFromFileListing(svn_constants.API_PATH) |
epeterson
2013/04/17 03:38:50
Instead of trying to load every file and check for
|
+ self._object_store.Set(version, names) |
+ api_name = model.UnixName(api_name) |
+ return api_name in names or self._GetAsSubdirectory(api_name) in names |
+ |
+ def FindEarliestAvailability(self, api_name): |
+ '''Searches in descending order through filesystem caches tied to specific |
+ chrome version numbers and looks for the existence of a specified api, |
+ |api_name|. When an api is not found, returns the previous version number |
+ (the last known version where the api was found). |
+ ''' |
+ availability = self._object_store.Get(api_name).Get() |
+ if availability is not None: |
+ return availability |
+ elif availability is False: |
+ return None |
+ |
+ # Check for a predetermined availability for this API. |
+ availability = self._existing_availabilities.get(api_name, None) |
+ if availability is not None: |
+ self._object_store.Set(api_name, availability) |
+ return availability |
+ |
+ # If the API isn't found in trunk, then it isn't currently available. |
+ if not self._CheckApiExistence(api_name, 'trunk'): |
+ self._object_store.Set(api_name, False) |
+ return None |
+ |
+ latest_version = int(self._chrome_version_utility.GetLatestVersionNumber()) |
+ version_int = latest_version |
+ # Extension APIs are not present in the filesystem before version 18. |
+ while version_int >= 18: |
+ if not self._CheckApiExistence(api_name, str(version_int)): |
+ break |
+ version_int -= 1 |
+ |
+ version_int += 1 |
+ if version_int > latest_version: |
+ availability = 'trunk' |
+ else: |
+ availability = str(version_int) |
+ |
+ self._object_store.Set(api_name, availability) |
+ return availability |