| Index: chrome/common/extensions/docs/server2/features_bundle.py
|
| diff --git a/chrome/common/extensions/docs/server2/features_bundle.py b/chrome/common/extensions/docs/server2/features_bundle.py
|
| index b8e9be5a20d77e6dfc651dfc99310bf57115b42d..1cceafda61c2ae111ec284b9c5c4ffafbd496a1d 100644
|
| --- a/chrome/common/extensions/docs/server2/features_bundle.py
|
| +++ b/chrome/common/extensions/docs/server2/features_bundle.py
|
| @@ -9,7 +9,7 @@ from compiled_file_system import SingleFile, Unicode
|
| from docs_server_utils import StringIdentity
|
| from extensions_paths import API_PATHS, JSON_TEMPLATES
|
| from file_system import FileNotFoundError
|
| -from future import Future
|
| +from future import All, Future
|
| from path_util import Join
|
| from platform_util import GetExtensionTypes, PlatformToExtensionType
|
| from third_party.json_schema_compiler.json_parse import Parse
|
| @@ -308,66 +308,74 @@ class FeaturesBundle(object):
|
| '''Resolves all dependencies in the categories specified by |dependencies|.
|
| Returns the features in the |features_type| category.
|
| '''
|
| - features = self._object_store.Get(features_type).Get()
|
| - if features is not None:
|
| - return Future(value=features)
|
| -
|
| - futures = {}
|
| - for cache_type in dependencies:
|
| - dependency_features = self._object_store.Get(cache_type).Get()
|
| - if dependency_features is not None:
|
| - # Get cached dependencies if possible. If it has been cached, all
|
| - # of its features have been resolved, so the other fields are
|
| - # unnecessary.
|
| - futures[cache_type] = Future(value={'resolved': dependency_features})
|
| - else:
|
| - futures[cache_type] = self._caches[cache_type].GetFeatures()
|
| -
|
| - def resolve():
|
| - features_map = {}
|
| - for cache_type, future in futures.iteritems():
|
| - # Copy down to features_map level because the 'resolved' and
|
| - # 'unresolved' dicts will be modified.
|
| - features_map[cache_type] = dict((c, copy(d))
|
| - for c, d in future.Get().iteritems())
|
| -
|
| - def has_unresolved():
|
| - '''Determines if there are any unresolved features left over in any
|
| - of the categories in |dependencies|.
|
| - '''
|
| - return any(cache.get('unresolved')
|
| - for cache in features_map.itervalues())
|
| -
|
| - # Iterate until everything is resolved. If dependencies are multiple
|
| - # levels deep, it might take multiple passes to inherit data to the
|
| - # topmost feature.
|
| - while has_unresolved():
|
| - for cache_type, cache in features_map.iteritems():
|
| - if 'unresolved' not in cache:
|
| - continue
|
| - to_remove = []
|
| - for feature_name, feature_values in cache['unresolved'].iteritems():
|
| - resolve_successful, feature = _ResolveFeature(
|
| - feature_name,
|
| - feature_values,
|
| - cache['extra'].get(feature_name, ()),
|
| - self._platform,
|
| - cache_type,
|
| - features_map)
|
| - if not resolve_successful:
|
| - continue # Try again on the next iteration of the while loop
|
| -
|
| - # When successfully resolved, remove it from the unresolved dict.
|
| - # Add it to the resolved dict if it didn't get deleted.
|
| - to_remove.append(feature_name)
|
| - if feature is not None:
|
| - cache['resolved'][feature_name] = feature
|
| -
|
| - for key in to_remove:
|
| - del cache['unresolved'][key]
|
| -
|
| - for cache_type, cache in features_map.iteritems():
|
| - self._object_store.Set(cache_type, cache['resolved'])
|
| - return features_map[features_type]['resolved']
|
| -
|
| - return Future(callback=resolve)
|
| + def next_(features):
|
| + if features is not None:
|
| + return Future(value=features)
|
| +
|
| + dependency_futures = []
|
| + cache_types = []
|
| + for cache_type in dependencies:
|
| + cache_types.append(cache_type)
|
| + dependency_futures.append(self._object_store.Get(cache_type))
|
| +
|
| + def load_features(dependency_features_list):
|
| + futures = []
|
| + for dependency_features, cache_type in zip(dependency_features_list,
|
| + cache_types):
|
| + if dependency_features is not None:
|
| + # Get cached dependencies if possible. If it has been cached, all
|
| + # of its features have been resolved, so the other fields are
|
| + # unnecessary.
|
| + futures.append(Future(value={'resolved': dependency_features}))
|
| + else:
|
| + futures.append(self._caches[cache_type].GetFeatures())
|
| +
|
| + def resolve(features):
|
| + features_map = {}
|
| + for cache_type, feature in zip(cache_types, features):
|
| + # Copy down to features_map level because the 'resolved' and
|
| + # 'unresolved' dicts will be modified.
|
| + features_map[cache_type] = dict((c, copy(d))
|
| + for c, d in feature.iteritems())
|
| +
|
| + def has_unresolved():
|
| + '''Determines if there are any unresolved features left over in any
|
| + of the categories in |dependencies|.
|
| + '''
|
| + return any(cache.get('unresolved')
|
| + for cache in features_map.itervalues())
|
| +
|
| + # Iterate until everything is resolved. If dependencies are multiple
|
| + # levels deep, it might take multiple passes to inherit data to the
|
| + # topmost feature.
|
| + while has_unresolved():
|
| + for cache_type, cache in features_map.iteritems():
|
| + if 'unresolved' not in cache:
|
| + continue
|
| + to_remove = []
|
| + for name, values in cache['unresolved'].iteritems():
|
| + resolve_successful, feature = _ResolveFeature(
|
| + name,
|
| + values,
|
| + cache['extra'].get(name, ()),
|
| + self._platform,
|
| + cache_type,
|
| + features_map)
|
| + if not resolve_successful:
|
| + continue # Try again on the next iteration of the while loop
|
| +
|
| + # When successfully resolved, remove it from the unresolved
|
| + # dict. Add it to the resolved dict if it didn't get deleted.
|
| + to_remove.append(name)
|
| + if feature is not None:
|
| + cache['resolved'][name] = feature
|
| +
|
| + for key in to_remove:
|
| + del cache['unresolved'][key]
|
| +
|
| + for cache_type, cache in features_map.iteritems():
|
| + self._object_store.Set(cache_type, cache['resolved'])
|
| + return features_map[features_type]['resolved']
|
| + return All(futures).Then(resolve)
|
| + return All(dependency_futures).Then(load_features)
|
| + return self._object_store.Get(features_type).Then(next_)
|
|
|