from copy import deepcopy from itertools import product from pythonforandroid.logger import info from pythonforandroid.recipe import Recipe from pythonforandroid.bootstrap import Bootstrap from pythonforandroid.util import BuildInterruptingException def fix_deplist(deps): """ Turn a dependency list into lowercase, and make sure all entries that are just a string become a tuple of strings """ deps = [ ((dep.lower(),) if not isinstance(dep, (list, tuple)) else tuple([dep_entry.lower() for dep_entry in dep ])) for dep in deps ] return deps class RecipeOrder(dict): def __init__(self, ctx): self.ctx = ctx def conflicts(self): for name in self.keys(): try: recipe = Recipe.get_recipe(name, self.ctx) conflicts = [dep.lower() for dep in recipe.conflicts] except ValueError: conflicts = [] if any([c in self for c in conflicts]): return True return False def get_dependency_tuple_list_for_recipe(recipe, blacklist=None): """ Get the dependencies of a recipe with filtered out blacklist, and turned into tuples with fix_deplist() """ if blacklist is None: blacklist = set() assert(type(blacklist) == set) if recipe.depends is None: dependencies = [] else: # Turn all dependencies into tuples so that product will work dependencies = fix_deplist(recipe.depends) # Filter out blacklisted items and turn lowercase: dependencies = [ tuple(set(deptuple) - blacklist) for deptuple in dependencies if tuple(set(deptuple) - blacklist) ] return dependencies def recursively_collect_orders( name, ctx, all_inputs, orders=None, blacklist=None ): '''For each possible recipe ordering, try to add the new recipe name to that order. Recursively do the same thing with all the dependencies of each recipe. ''' name = name.lower() if orders is None: orders = [] if blacklist is None: blacklist = set() try: recipe = Recipe.get_recipe(name, ctx) dependencies = get_dependency_tuple_list_for_recipe( recipe, blacklist=blacklist ) # handle opt_depends: these impose requirements on the build # order only if already present in the list of recipes to build dependencies.extend(fix_deplist( [[d] for d in recipe.get_opt_depends_in_list(all_inputs) if d.lower() not in blacklist] )) if recipe.conflicts is None: conflicts = [] else: conflicts = [dep.lower() for dep in recipe.conflicts] except ValueError: # The recipe does not exist, so we assume it can be installed # via pip with no extra dependencies dependencies = [] conflicts = [] new_orders = [] # for each existing recipe order, see if we can add the new recipe name for order in orders: if name in order: new_orders.append(deepcopy(order)) continue if order.conflicts(): continue if any([conflict in order for conflict in conflicts]): continue for dependency_set in product(*dependencies): new_order = deepcopy(order) new_order[name]