OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 from copy import copy | 5 from copy import copy |
6 | 6 |
7 from branch_utility import BranchUtility | 7 from branch_utility import BranchUtility |
8 from compiled_file_system import SingleFile, Unicode | 8 from compiled_file_system import SingleFile, Unicode |
9 from docs_server_utils import StringIdentity | 9 from docs_server_utils import StringIdentity |
10 from extensions_paths import API_PATHS, JSON_TEMPLATES | 10 from extensions_paths import API_PATHS, JSON_TEMPLATES |
11 from file_system import FileNotFoundError | 11 from file_system import FileNotFoundError |
12 from future import Future | 12 from future import All, Future |
13 from path_util import Join | 13 from path_util import Join |
14 from platform_util import GetExtensionTypes, PlatformToExtensionType | 14 from platform_util import GetExtensionTypes, PlatformToExtensionType |
15 from third_party.json_schema_compiler.json_parse import Parse | 15 from third_party.json_schema_compiler.json_parse import Parse |
16 | 16 |
17 | 17 |
18 _API_FEATURES = '_api_features.json' | 18 _API_FEATURES = '_api_features.json' |
19 _MANIFEST_FEATURES = '_manifest_features.json' | 19 _MANIFEST_FEATURES = '_manifest_features.json' |
20 _PERMISSION_FEATURES = '_permission_features.json' | 20 _PERMISSION_FEATURES = '_permission_features.json' |
21 | 21 |
22 | 22 |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 def GetManifestFeatures(self): | 301 def GetManifestFeatures(self): |
302 return self.GetFeatures('manifest', ('manifest',)) | 302 return self.GetFeatures('manifest', ('manifest',)) |
303 | 303 |
304 def GetAPIFeatures(self): | 304 def GetAPIFeatures(self): |
305 return self.GetFeatures('api', ('api', 'manifest', 'permission')) | 305 return self.GetFeatures('api', ('api', 'manifest', 'permission')) |
306 | 306 |
307 def GetFeatures(self, features_type, dependencies): | 307 def GetFeatures(self, features_type, dependencies): |
308 '''Resolves all dependencies in the categories specified by |dependencies|. | 308 '''Resolves all dependencies in the categories specified by |dependencies|. |
309 Returns the features in the |features_type| category. | 309 Returns the features in the |features_type| category. |
310 ''' | 310 ''' |
311 features = self._object_store.Get(features_type).Get() | 311 def next_(features): |
312 if features is not None: | 312 if features is not None: |
313 return Future(value=features) | 313 return Future(value=features) |
314 | 314 |
315 futures = {} | 315 dependency_futures = [] |
316 for cache_type in dependencies: | 316 cache_types = [] |
317 dependency_features = self._object_store.Get(cache_type).Get() | 317 for cache_type in dependencies: |
318 if dependency_features is not None: | 318 cache_types.append(cache_type) |
319 # Get cached dependencies if possible. If it has been cached, all | 319 dependency_futures.append(self._object_store.Get(cache_type)) |
320 # of its features have been resolved, so the other fields are | |
321 # unnecessary. | |
322 futures[cache_type] = Future(value={'resolved': dependency_features}) | |
323 else: | |
324 futures[cache_type] = self._caches[cache_type].GetFeatures() | |
325 | 320 |
326 def resolve(): | 321 def load_features(dependency_features_list): |
327 features_map = {} | 322 futures = [] |
328 for cache_type, future in futures.iteritems(): | 323 for dependency_features, cache_type in zip(dependency_features_list, |
329 # Copy down to features_map level because the 'resolved' and | 324 cache_types): |
330 # 'unresolved' dicts will be modified. | 325 if dependency_features is not None: |
331 features_map[cache_type] = dict((c, copy(d)) | 326 # Get cached dependencies if possible. If it has been cached, all |
332 for c, d in future.Get().iteritems()) | 327 # of its features have been resolved, so the other fields are |
| 328 # unnecessary. |
| 329 futures.append(Future(value={'resolved': dependency_features})) |
| 330 else: |
| 331 futures.append(self._caches[cache_type].GetFeatures()) |
333 | 332 |
334 def has_unresolved(): | 333 def resolve(features): |
335 '''Determines if there are any unresolved features left over in any | 334 features_map = {} |
336 of the categories in |dependencies|. | 335 for cache_type, feature in zip(cache_types, features): |
337 ''' | 336 # Copy down to features_map level because the 'resolved' and |
338 return any(cache.get('unresolved') | 337 # 'unresolved' dicts will be modified. |
339 for cache in features_map.itervalues()) | 338 features_map[cache_type] = dict((c, copy(d)) |
| 339 for c, d in feature.iteritems()) |
340 | 340 |
341 # Iterate until everything is resolved. If dependencies are multiple | 341 def has_unresolved(): |
342 # levels deep, it might take multiple passes to inherit data to the | 342 '''Determines if there are any unresolved features left over in any |
343 # topmost feature. | 343 of the categories in |dependencies|. |
344 while has_unresolved(): | 344 ''' |
345 for cache_type, cache in features_map.iteritems(): | 345 return any(cache.get('unresolved') |
346 if 'unresolved' not in cache: | 346 for cache in features_map.itervalues()) |
347 continue | |
348 to_remove = [] | |
349 for feature_name, feature_values in cache['unresolved'].iteritems(): | |
350 resolve_successful, feature = _ResolveFeature( | |
351 feature_name, | |
352 feature_values, | |
353 cache['extra'].get(feature_name, ()), | |
354 self._platform, | |
355 cache_type, | |
356 features_map) | |
357 if not resolve_successful: | |
358 continue # Try again on the next iteration of the while loop | |
359 | 347 |
360 # When successfully resolved, remove it from the unresolved dict. | 348 # Iterate until everything is resolved. If dependencies are multiple |
361 # Add it to the resolved dict if it didn't get deleted. | 349 # levels deep, it might take multiple passes to inherit data to the |
362 to_remove.append(feature_name) | 350 # topmost feature. |
363 if feature is not None: | 351 while has_unresolved(): |
364 cache['resolved'][feature_name] = feature | 352 for cache_type, cache in features_map.iteritems(): |
| 353 if 'unresolved' not in cache: |
| 354 continue |
| 355 to_remove = [] |
| 356 for name, values in cache['unresolved'].iteritems(): |
| 357 resolve_successful, feature = _ResolveFeature( |
| 358 name, |
| 359 values, |
| 360 cache['extra'].get(name, ()), |
| 361 self._platform, |
| 362 cache_type, |
| 363 features_map) |
| 364 if not resolve_successful: |
| 365 continue # Try again on the next iteration of the while loop |
365 | 366 |
366 for key in to_remove: | 367 # When successfully resolved, remove it from the unresolved |
367 del cache['unresolved'][key] | 368 # dict. Add it to the resolved dict if it didn't get deleted. |
| 369 to_remove.append(name) |
| 370 if feature is not None: |
| 371 cache['resolved'][name] = feature |
368 | 372 |
369 for cache_type, cache in features_map.iteritems(): | 373 for key in to_remove: |
370 self._object_store.Set(cache_type, cache['resolved']) | 374 del cache['unresolved'][key] |
371 return features_map[features_type]['resolved'] | |
372 | 375 |
373 return Future(callback=resolve) | 376 for cache_type, cache in features_map.iteritems(): |
| 377 self._object_store.Set(cache_type, cache['resolved']) |
| 378 return features_map[features_type]['resolved'] |
| 379 return All(futures).Then(resolve) |
| 380 return All(dependency_futures).Then(load_features) |
| 381 return self._object_store.Get(features_type).Then(next_) |
OLD | NEW |