#
# Jasy - Web Tooling Framework
# Copyright 2010-2012 Zynga Inc.
# Copyright 2013-2014 Sebastian Werner
#
import jasy.core.Console as Console
import jasy.item.Abstract as AbstractItem
[docs]class ResolverError(Exception):
"""Error which is throws when resolving items could be be finished because of items which could not be found or are
of an unexpected type."""
pass
[docs]class Resolver():
"""
Resolves dependencies between items.
This class is not type depended e.g. is used for both scripts and styles.
"""
def __init__(self, profile):
# Keep profile reference
self.profile = profile
# Keep permutation reference
self.permutation = profile.getCurrentPermutation()
# Collecting all available items
self.items = {}
# Required classes by the user
self.__required = []
# Hard excluded classes (used for filtering previously included classes etc.)
self.__excluded = []
# Included classes after dependency calculation
self.__included = []
[docs] def add(self, nameOrItem, prepend=False):
"""Adds an item by its name or via the item instance."""
if isinstance(nameOrItem, str):
if not nameOrItem in self.items:
raise ResolverError("Unknown item: %s" % nameOrItem)
# Replace variable with item instance
nameOrItem = self.items[nameOrItem]
elif not isinstance(nameOrItem, AbstractItem.AbstractItem):
raise ResolverError("Invalid item: %s" % nameOrItem)
if prepend:
self.__required.insert(0, nameOrItem)
else:
self.__required.append(nameOrItem)
# Invalidate included list
self.__included = None
return self
[docs] def remove(self, nameOrItem):
"""Removes an item via its name or via the item instance."""
for item in self.__required:
if item is nameOrItem or item.getId() == nameOrItem:
self.__required.remove(item)
if self.__included:
self.__included = []
return True
return False
[docs] def exclude(self, items):
"""
Excludes the given items (just a hard-exclude which is
applied after calculating the current dependencies)
"""
self.__excluded.extend(items)
# Invalidate included list
self.__included = None
return self
[docs] def getRequired(self):
""" Returns the user added classes - the so-called required classes. """
return self.__required
[docs] def getIncluded(self):
"""Returns a final set of classes after resolving dependencies."""
if self.__included:
return self.__included
collection = set()
for item in self.__required:
self.__resolveDependencies(item, collection)
# Filter excluded classes
for item in self.__excluded:
if item in collection:
collection.remove(item)
self.__included = collection
return self.__included
def __resolveDependencies(self, item, collection):
"""Internal resolver engine which works recursively through all dependencies."""
collection.add(item)
dependencies = self.getItemDependencies(item)
for depObj in dependencies:
if depObj not in collection:
self.__resolveDependencies(depObj, collection)