summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-07 00:14:33 +0000
committerkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-07 00:14:33 +0000
commit9438e3b1b85d54c49e1237ff598d6ee358c9f02a (patch)
tree8c263123e700ad7f8ae3f7bae581373670876ce6
parente0cbfc49b0ecbde83ca6638f7f416fa119686d9c (diff)
downloadchromium_src-9438e3b1b85d54c49e1237ff598d6ee358c9f02a.zip
chromium_src-9438e3b1b85d54c49e1237ff598d6ee358c9f02a.tar.gz
chromium_src-9438e3b1b85d54c49e1237ff598d6ee358c9f02a.tar.bz2
Docserver: Make the hand-written Cron methods return a Future and run first
rather than last, so that they can be parallelised and have the most effect. Implement a few of the more trivial Cron methods, including moving most FeaturesBundle methods to return Futures. BUG=305280 R=jyasskin@chromium.org NOTRY=true Review URL: https://codereview.chromium.org/63203002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@233427 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/common/extensions/docs/server2/api_list_data_source.py2
-rw-r--r--chrome/common/extensions/docs/server2/api_models.py2
-rw-r--r--chrome/common/extensions/docs/server2/app.yaml2
-rw-r--r--chrome/common/extensions/docs/server2/content_provider.py6
-rw-r--r--chrome/common/extensions/docs/server2/content_providers.py6
-rw-r--r--chrome/common/extensions/docs/server2/cron.yaml2
-rw-r--r--chrome/common/extensions/docs/server2/cron_servlet.py63
-rwxr-xr-xchrome/common/extensions/docs/server2/cron_servlet_test.py5
-rw-r--r--chrome/common/extensions/docs/server2/features_bundle.py41
-rwxr-xr-xchrome/common/extensions/docs/server2/features_bundle_test.py6
-rw-r--r--chrome/common/extensions/docs/server2/manifest_data_source.py35
-rwxr-xr-xchrome/common/extensions/docs/server2/manifest_data_source_test.py3
-rw-r--r--chrome/common/extensions/docs/server2/permissions_data_source.py46
-rw-r--r--chrome/common/extensions/docs/server2/redirector.py6
-rwxr-xr-xchrome/common/extensions/docs/server2/redirector_test.py2
-rw-r--r--chrome/common/extensions/docs/server2/sidenav_data_source.py3
-rwxr-xr-xchrome/common/extensions/docs/server2/sidenav_data_source_test.py2
-rw-r--r--chrome/common/extensions/docs/server2/strings_data_source.py7
-rw-r--r--chrome/common/extensions/docs/server2/template_data_source.py3
19 files changed, 152 insertions, 90 deletions
diff --git a/chrome/common/extensions/docs/server2/api_list_data_source.py b/chrome/common/extensions/docs/server2/api_list_data_source.py
index 4efe5ca..59f62d1 100644
--- a/chrome/common/extensions/docs/server2/api_list_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_list_data_source.py
@@ -66,7 +66,7 @@ class APIListDataSource(object):
def _GenerateAPIDict(self):
documented_apis = self._cache.GetFromFileListing(
PUBLIC_TEMPLATE_PATH).Get()
- api_features = self._features_bundle.GetAPIFeatures()
+ api_features = self._features_bundle.GetAPIFeatures().Get()
def FilterAPIs(platform):
return (api for api in api_features.itervalues()
diff --git a/chrome/common/extensions/docs/server2/api_models.py b/chrome/common/extensions/docs/server2/api_models.py
index e05f59d..e55ccb8 100644
--- a/chrome/common/extensions/docs/server2/api_models.py
+++ b/chrome/common/extensions/docs/server2/api_models.py
@@ -36,7 +36,7 @@ class APIModels(object):
# features file. APIs are those which either implicitly or explicitly have
# no parent feature (e.g. app, app.window, and devtools.inspectedWindow are
# APIs; runtime.onConnectNative is not).
- api_features = self._features_bundle.GetAPIFeatures()
+ api_features = self._features_bundle.GetAPIFeatures().Get()
return [name for name, feature in api_features.iteritems()
if ('.' not in name or
name.rsplit('.', 1)[0] not in api_features or
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index eb3db71..d1a5699 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
application: chrome-apps-doc
-version: 2-38-1
+version: 2-38-2
runtime: python27
api_version: 1
threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/content_provider.py b/chrome/common/extensions/docs/server2/content_provider.py
index 11ec8f2..cf2ce01 100644
--- a/chrome/common/extensions/docs/server2/content_provider.py
+++ b/chrome/common/extensions/docs/server2/content_provider.py
@@ -85,5 +85,7 @@ class ContentProvider(object):
def Cron(self):
# Running Refresh() on the file system is enough to pull GitHub content,
- # which is all we need for now.
- self.file_system.Refresh().Get()
+ # which is all we need for now while the full render-every-page cron step
+ # is in effect.
+ # TODO(kalman): Walk over the whole filesystem and compile the content.
+ return self.file_system.Refresh()
diff --git a/chrome/common/extensions/docs/server2/content_providers.py b/chrome/common/extensions/docs/server2/content_providers.py
index e8bcc07..cddc87a 100644
--- a/chrome/common/extensions/docs/server2/content_providers.py
+++ b/chrome/common/extensions/docs/server2/content_providers.py
@@ -8,6 +8,7 @@ import posixpath
from chroot_file_system import ChrootFileSystem
from content_provider import ContentProvider
+from future import Gettable, Future
from svn_constants import JSON_PATH
from third_party.json_schema_compiler.memoize import memoize
@@ -102,5 +103,6 @@ class ContentProviders(object):
supports_zip=supports_zip)
def Cron(self):
- for name, config in self._GetConfig().iteritems():
- self._CreateContentProvider(name, config).Cron()
+ futures = [self._CreateContentProvider(name, config).Cron()
+ for name, config in self._GetConfig().iteritems()]
+ return Future(delegate=Gettable(lambda: [f.Get() for f in futures]))
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
index 3debfe4..7ea299a 100644
--- a/chrome/common/extensions/docs/server2/cron.yaml
+++ b/chrome/common/extensions/docs/server2/cron.yaml
@@ -2,4 +2,4 @@ cron:
- description: Repopulates all cached data.
url: /_cron
schedule: every 5 minutes
- target: 2-38-1
+ target: 2-38-2
diff --git a/chrome/common/extensions/docs/server2/cron_servlet.py b/chrome/common/extensions/docs/server2/cron_servlet.py
index aa37ae3..7865aa0 100644
--- a/chrome/common/extensions/docs/server2/cron_servlet.py
+++ b/chrome/common/extensions/docs/server2/cron_servlet.py
@@ -15,6 +15,7 @@ from data_source_registry import CreateDataSources
from empty_dir_file_system import EmptyDirFileSystem
from environment import IsDevServer
from file_system_util import CreateURLsFromPaths
+from future import Gettable, Future
from github_file_system_provider import GithubFileSystemProvider
from host_file_system_provider import HostFileSystemProvider
from object_store_creator import ObjectStoreCreator
@@ -151,6 +152,41 @@ class CronServlet(Servlet):
results = []
try:
+ # Start running the hand-written Cron methods first; they can be run in
+ # parallel. They are resolved at the end.
+ def run_cron_for_future(target):
+ title = target.__class__.__name__
+ start_time = time.time()
+ future = target.Cron()
+ init_time = time.time() - start_time
+ assert isinstance(future, Future), (
+ '%s.Cron() did not return a Future' % title)
+ def resolve():
+ start_time = time.time()
+ try:
+ future.Get()
+ except Exception as e:
+ _cronlog.error('%s: error %s' % (title, traceback.format_exc()))
+ results.append(False)
+ if IsDeadlineExceededError(e): raise
+ finally:
+ resolve_time = time.time() - start_time
+ _cronlog.info(
+ '%s: used %s seconds, %s to initialize and %s to resolve' %
+ (title, init_time + resolve_time, init_time, resolve_time))
+ return Future(delegate=Gettable(resolve))
+
+ targets = (CreateDataSources(server_instance).values() +
+ [server_instance.content_providers])
+ title = 'initializing %s parallel Cron targets' % len(targets)
+ start_time = time.time()
+ _cronlog.info(title)
+ try:
+ cron_futures = [run_cron_for_future(target) for target in targets]
+ finally:
+ _cronlog.info('%s took %s seconds' % (title, time.time() - start_time))
+
+
# Rendering the public templates will also pull in all of the private
# templates.
results.append(request_files_in_dir(svn_constants.PUBLIC_TEMPLATE_PATH))
@@ -179,24 +215,15 @@ class CronServlet(Servlet):
example_zips,
lambda path: render('extensions/examples/' + path)))
- def run_cron(data_source):
- title = data_source.__class__.__name__
- _cronlog.info('%s: starting' % title)
- start_time = time.time()
- try:
- data_source.Cron()
- except Exception as e:
- _cronlog.error('%s: error %s' % (title, traceback.format_exc()))
- results.append(False)
- if IsDeadlineExceededError(e): raise
- finally:
- _cronlog.info(
- '%s: took %s seconds' % (title, time.time() - start_time))
-
- for data_source in CreateDataSources(server_instance).values():
- run_cron(data_source)
-
- run_cron(server_instance.content_providers)
+ # Resolve the hand-written Cron method futures.
+ title = 'resolving %s parallel Cron targets' % len(targets)
+ _cronlog.info(title)
+ start_time = time.time()
+ try:
+ for future in cron_futures:
+ future.Get()
+ finally:
+ _cronlog.info('%s took %s seconds' % (title, time.time() - start_time))
except:
results.append(False)
diff --git a/chrome/common/extensions/docs/server2/cron_servlet_test.py b/chrome/common/extensions/docs/server2/cron_servlet_test.py
index 371d100..e3538e5 100755
--- a/chrome/common/extensions/docs/server2/cron_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/cron_servlet_test.py
@@ -85,7 +85,9 @@ class CronServletTest(unittest.TestCase):
def testSafeRevision(self):
test_data = {
'api': {
- '_manifest_features.json': '{}'
+ '_api_features.json': '{}',
+ '_manifest_features.json': '{}',
+ '_permission_features.json': '{}',
},
'docs': {
'examples': {
@@ -110,6 +112,7 @@ class CronServletTest(unittest.TestCase):
'content_providers.json': ReadFile('%s/content_providers.json' %
JSON_PATH),
'manifest.json': '{}',
+ 'permissions.json': '{}',
'strings.json': '{}',
'apps_sidenav.json': '{}',
'extensions_sidenav.json': '{}',
diff --git a/chrome/common/extensions/docs/server2/features_bundle.py b/chrome/common/extensions/docs/server2/features_bundle.py
index d11d5ac..ffa0f79 100644
--- a/chrome/common/extensions/docs/server2/features_bundle.py
+++ b/chrome/common/extensions/docs/server2/features_bundle.py
@@ -3,15 +3,19 @@
# found in the LICENSE file.
import features_utility
+from future import Gettable, Future
import svn_constants
from third_party.json_schema_compiler.json_parse import Parse
-def _AddPlatformsFromDependencies(feature, features_bundle):
+def _AddPlatformsFromDependencies(feature,
+ api_features,
+ manifest_features,
+ permission_features):
features_map = {
- 'api': features_bundle.GetAPIFeatures(),
- 'manifest': features_bundle.GetManifestFeatures(),
- 'permission': features_bundle.GetPermissionFeatures()
+ 'api': api_features,
+ 'manifest': manifest_features,
+ 'permission': permission_features,
}
dependencies = feature.get('dependencies')
if dependencies is None:
@@ -38,17 +42,19 @@ class _FeaturesCache(object):
self._extra_paths = json_paths[1:]
def _CreateCache(self, _, features_json):
+ extra_path_futures = [self._file_system.ReadSingle(path)
+ for path in self._extra_paths]
features = features_utility.Parse(Parse(features_json))
- for path in self._extra_paths:
- extra_json = self._file_system.ReadSingle(path).Get()
+ for path_future in extra_path_futures:
+ extra_json = path_future.Get()
features = features_utility.MergedWith(
features_utility.Parse(Parse(extra_json)), features)
return features
def GetFeatures(self):
if self._json_path is None:
- return {}
- return self._cache.GetFromFile(self._json_path).Get()
+ return Future(value={})
+ return self._cache.GetFromFile(self._json_path)
class FeaturesBundle(object):
@@ -79,14 +85,23 @@ class FeaturesBundle(object):
def GetAPIFeatures(self):
api_features = self._object_store.Get('api_features').Get()
- if api_features is None:
- api_features = self._api_cache.GetFeatures()
+ if api_features is not None:
+ return Future(value=api_features)
+
+ api_features_future = self._api_cache.GetFeatures()
+ manifest_features_future = self._manifest_cache.GetFeatures()
+ permission_features_future = self._permission_cache.GetFeatures()
+ def resolve():
+ api_features = api_features_future.Get()
+ manifest_features = manifest_features_future.Get()
+ permission_features = permission_features_future.Get()
# TODO(rockot): Handle inter-API dependencies more gracefully.
# Not yet a problem because there is only one such case (windows -> tabs).
# If we don't store this value before annotating platforms, inter-API
# dependencies will lead to infinite recursion.
- self._object_store.Set('api_features', api_features)
for feature in api_features.itervalues():
- _AddPlatformsFromDependencies(feature, self)
+ _AddPlatformsFromDependencies(
+ feature, api_features, manifest_features, permission_features)
self._object_store.Set('api_features', api_features)
- return api_features
+ return api_features
+ return Future(delegate=Gettable(resolve))
diff --git a/chrome/common/extensions/docs/server2/features_bundle_test.py b/chrome/common/extensions/docs/server2/features_bundle_test.py
index 842ee09..fb9cbaf 100755
--- a/chrome/common/extensions/docs/server2/features_bundle_test.py
+++ b/chrome/common/extensions/docs/server2/features_bundle_test.py
@@ -173,7 +173,7 @@ class FeaturesBundleTest(unittest.TestCase):
}
self.assertEqual(
expected_features,
- self._server.features_bundle.GetManifestFeatures())
+ self._server.features_bundle.GetManifestFeatures().Get())
def testPermissionFeatures(self):
expected_features = {
@@ -206,7 +206,7 @@ class FeaturesBundleTest(unittest.TestCase):
}
self.assertEqual(
expected_features,
- self._server.features_bundle.GetPermissionFeatures())
+ self._server.features_bundle.GetPermissionFeatures().Get())
def testAPIFeatures(self):
expected_features = {
@@ -254,7 +254,7 @@ class FeaturesBundleTest(unittest.TestCase):
}
self.assertEqual(
expected_features,
- self._server.features_bundle.GetAPIFeatures())
+ self._server.features_bundle.GetAPIFeatures().Get())
if __name__ == '__main__':
unittest.main()
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source.py b/chrome/common/extensions/docs/server2/manifest_data_source.py
index ac4d99c..9daa5bb 100644
--- a/chrome/common/extensions/docs/server2/manifest_data_source.py
+++ b/chrome/common/extensions/docs/server2/manifest_data_source.py
@@ -6,6 +6,7 @@ import json
from data_source import DataSource
import features_utility
+from future import Gettable, Future
from manifest_features import ConvertDottedKeysToNested
from third_party.json_schema_compiler.json_parse import Parse
@@ -105,27 +106,29 @@ class ManifestDataSource(DataSource):
ManifestDataSource)
def _CreateManifestData(self):
- def for_templates(manifest_features, platform):
- return _AddLevelAnnotations(
- _ListifyAndSortDocs(
- ConvertDottedKeysToNested(
- features_utility.Filtered(manifest_features, platform)),
- app_name=platform.capitalize()))
- manifest_features = self._features_bundle.GetManifestFeatures()
- return {
- 'apps': for_templates(manifest_features, 'apps'),
- 'extensions': for_templates(manifest_features, 'extensions')
- }
-
- def _GetCachedManifestData(self, force_update=False):
+ future_manifest_features = self._features_bundle.GetManifestFeatures()
+ def resolve():
+ manifest_features = future_manifest_features.Get()
+ def for_templates(manifest_features, platform):
+ return _AddLevelAnnotations(_ListifyAndSortDocs(
+ ConvertDottedKeysToNested(
+ features_utility.Filtered(manifest_features, platform)),
+ app_name=platform.capitalize()))
+ return {
+ 'apps': for_templates(manifest_features, 'apps'),
+ 'extensions': for_templates(manifest_features, 'extensions')
+ }
+ return Future(delegate=Gettable(resolve))
+
+ def _GetCachedManifestData(self):
data = self._object_store.Get('manifest_data').Get()
- if data is None or force_update:
- data = self._CreateManifestData()
+ if data is None:
+ data = self._CreateManifestData().Get()
self._object_store.Set('manifest_data', data)
return data
def Cron(self):
- self._GetCachedManifestData(force_update=True)
+ return self._CreateManifestData()
def get(self, key):
return self._GetCachedManifestData().get(key)
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source_test.py b/chrome/common/extensions/docs/server2/manifest_data_source_test.py
index f9c99be..7742a49d 100755
--- a/chrome/common/extensions/docs/server2/manifest_data_source_test.py
+++ b/chrome/common/extensions/docs/server2/manifest_data_source_test.py
@@ -9,6 +9,7 @@ import unittest
from compiled_file_system import CompiledFileSystem
from features_bundle import FeaturesBundle
+from future import Future
import manifest_data_source
from object_store_creator import ObjectStoreCreator
@@ -246,7 +247,7 @@ class ManifestDataSourceTest(unittest.TestCase):
class FakeFeaturesBundle(object):
def GetManifestFeatures(self):
- return manifest_features
+ return Future(value=manifest_features)
class FakeServerInstance(object):
def __init__(self):
diff --git a/chrome/common/extensions/docs/server2/permissions_data_source.py b/chrome/common/extensions/docs/server2/permissions_data_source.py
index 7ee3056..072ec8c 100644
--- a/chrome/common/extensions/docs/server2/permissions_data_source.py
+++ b/chrome/common/extensions/docs/server2/permissions_data_source.py
@@ -7,6 +7,7 @@ from operator import itemgetter
from data_source import DataSource
import features_utility as features
+from future import Gettable, Future
from svn_constants import PRIVATE_TEMPLATE_PATH
from third_party.json_schema_compiler.json_parse import Parse
@@ -50,38 +51,39 @@ class PermissionsDataSource(DataSource):
server_instance.host_file_system_provider.GetTrunk())
def _CreatePermissionsData(self):
- api_features = self._features_bundle.GetAPIFeatures()
- permission_features = self._features_bundle.GetPermissionFeatures()
+ api_features_future = self._features_bundle.GetAPIFeatures()
+ permission_features_future = self._features_bundle.GetPermissionFeatures()
+ def resolve():
+ permission_features = permission_features_future.Get()
+ _AddDependencyDescriptions(permission_features, api_features_future.Get())
- def filter_for_platform(permissions, platform):
- return _ListifyPermissions(features.Filtered(permissions, platform))
+ # Turn partial templates into descriptions, ensure anchors are set.
+ for permission in permission_features.values():
+ if not 'anchor' in permission:
+ permission['anchor'] = permission['name']
+ if 'partial' in permission:
+ permission['description'] = self._template_cache.GetFromFile('%s/%s' %
+ (PRIVATE_TEMPLATE_PATH, permission['partial'])).Get()
+ del permission['partial']
- _AddDependencyDescriptions(permission_features, api_features)
- # Turn partial templates into descriptions, ensure anchors are set.
- for permission in permission_features.values():
- if not 'anchor' in permission:
- permission['anchor'] = permission['name']
- if 'partial' in permission:
- permission['description'] = self._template_cache.GetFromFile('%s/%s' %
- (PRIVATE_TEMPLATE_PATH, permission['partial'])).Get()
- del permission['partial']
-
- return {
- 'declare_apps': filter_for_platform(permission_features, 'apps'),
- 'declare_extensions': filter_for_platform(
- permission_features, 'extensions')
- }
+ def filter_for_platform(permissions, platform):
+ return _ListifyPermissions(features.Filtered(permissions, platform))
+ return {
+ 'declare_apps': filter_for_platform(permission_features, 'apps'),
+ 'declare_extensions': filter_for_platform(
+ permission_features, 'extensions')
+ }
+ return Future(delegate=Gettable(resolve))
def _GetCachedPermissionsData(self):
data = self._object_store.Get('permissions_data').Get()
if data is None:
- data = self._CreatePermissionsData()
+ data = self._CreatePermissionsData().Get()
self._object_store.Set('permissions_data', data)
return data
def Cron(self):
- # TODO(kalman): Implement this.
- pass
+ return self._CreatePermissionsData()
def get(self, key):
return self._GetCachedPermissionsData().get(key)
diff --git a/chrome/common/extensions/docs/server2/redirector.py b/chrome/common/extensions/docs/server2/redirector.py
index c5e3635..acbc160 100644
--- a/chrome/common/extensions/docs/server2/redirector.py
+++ b/chrome/common/extensions/docs/server2/redirector.py
@@ -6,6 +6,7 @@ import posixpath
from urlparse import urlsplit
from file_system import FileNotFoundError
+from future import Gettable, Future
class Redirector(object):
def __init__(self, compiled_fs_factory, file_system):
@@ -60,6 +61,9 @@ class Redirector(object):
def Cron(self):
''' Load files during a cron run.
'''
+ futures = []
for root, dirs, files in self._file_system.Walk(''):
if 'redirects.json' in files:
- self._cache.GetFromFile(posixpath.join(root, 'redirects.json')).Get()
+ futures.append(
+ self._cache.GetFromFile(posixpath.join(root, 'redirects.json')))
+ return Future(delegate=Gettable(lambda: [f.Get() for f in futures]))
diff --git a/chrome/common/extensions/docs/server2/redirector_test.py b/chrome/common/extensions/docs/server2/redirector_test.py
index d5f5855..0eb404e 100755
--- a/chrome/common/extensions/docs/server2/redirector_test.py
+++ b/chrome/common/extensions/docs/server2/redirector_test.py
@@ -87,7 +87,7 @@ class RedirectorTest(unittest.TestCase):
self._redirector.Redirect('https://code.google.com', ''))
def testCron(self):
- self._redirector.Cron()
+ self._redirector.Cron().Get()
expected_paths = set([
'redirects.json',
diff --git a/chrome/common/extensions/docs/server2/sidenav_data_source.py b/chrome/common/extensions/docs/server2/sidenav_data_source.py
index 9364d72..a6b440e 100644
--- a/chrome/common/extensions/docs/server2/sidenav_data_source.py
+++ b/chrome/common/extensions/docs/server2/sidenav_data_source.py
@@ -80,8 +80,7 @@ class SidenavDataSource(DataSource):
futures = [
self._cache.GetFromFile('%s/%s_sidenav.json' % (JSON_PATH, platform))
for platform in ('apps', 'extensions')]
- for future in futures:
- future.Get()
+ return Future(delegate=Gettable(lambda: [f.Get() for f in futures]))
def get(self, key):
sidenav = copy.deepcopy(self._cache.GetFromFile(
diff --git a/chrome/common/extensions/docs/server2/sidenav_data_source_test.py b/chrome/common/extensions/docs/server2/sidenav_data_source_test.py
index 00104d7..6ad07a3 100755
--- a/chrome/common/extensions/docs/server2/sidenav_data_source_test.py
+++ b/chrome/common/extensions/docs/server2/sidenav_data_source_test.py
@@ -151,7 +151,7 @@ class SamplesDataSourceTest(unittest.TestCase):
# Ensure Cron doesn't rely on request.
sidenav_data_source = SidenavDataSource(
ServerInstance.ForTest(file_system), request=None)
- sidenav_data_source.Cron()
+ sidenav_data_source.Cron().Get()
# If Cron fails, apps_sidenav.json will not be cached, and the _cache_data
# access will fail.
diff --git a/chrome/common/extensions/docs/server2/strings_data_source.py b/chrome/common/extensions/docs/server2/strings_data_source.py
index d182add..3d7e513 100644
--- a/chrome/common/extensions/docs/server2/strings_data_source.py
+++ b/chrome/common/extensions/docs/server2/strings_data_source.py
@@ -13,8 +13,11 @@ class StringsDataSource(DataSource):
server_instance.host_file_system_provider.GetTrunk())
self._strings_json_path = server_instance.strings_json_path
+ def _GetStringsData(self):
+ return self._cache.GetFromFile(self._strings_json_path)
+
def Cron(self):
- self._cache.GetFromFile(self._strings_json_path).Get()
+ return self._GetStringsData()
def get(self, key):
- return self._cache.GetFromFile(self._strings_json_path).Get()[key]
+ return self._GetStringsData().Get().get(key)
diff --git a/chrome/common/extensions/docs/server2/template_data_source.py b/chrome/common/extensions/docs/server2/template_data_source.py
index 9345694..1a26803 100644
--- a/chrome/common/extensions/docs/server2/template_data_source.py
+++ b/chrome/common/extensions/docs/server2/template_data_source.py
@@ -9,6 +9,7 @@ import traceback
from data_source import DataSource
from docs_server_utils import FormatKey
from file_system import FileNotFoundError
+from future import Future
from svn_constants import PRIVATE_TEMPLATE_PATH
@@ -32,4 +33,4 @@ class TemplateDataSource(DataSource):
def Cron(self):
# TODO(kalman): Implement this; probably by finding all files that can be
# compiled to templates underneath |self._partial_dir| and compiling them.
- pass
+ return Future(value=())