Skip to content

Fixed some bugs with recipe graph calculations #641

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions pythonforandroid/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,22 +135,24 @@ def get_bootstrap_from_recipes(cls, recipes, ctx):
for name in cls.list_bootstraps()]
acceptable_bootstraps = []
for bs in bootstraps:
ok = True
if not bs.can_be_chosen_automatically:
ok = False
for recipe in bs.recipe_depends:
recipe = Recipe.get_recipe(recipe, ctx)
if any([conflict in recipes for conflict in recipe.conflicts]):
ok = False
break
for recipe in recipes:
recipe = Recipe.get_recipe(recipe, ctx)
if any([conflict in bs.recipe_depends
for conflict in recipe.conflicts]):
ok = False
break
if ok:
acceptable_bootstraps.append(bs)
continue
possible_dependency_lists = expand_dependencies(bs.recipe_depends)
for possible_dependencies in possible_dependency_lists:
ok = True
for recipe in possible_dependencies:
recipe = Recipe.get_recipe(recipe, ctx)
if any([conflict in recipes for conflict in recipe.conflicts]):
ok = False
break
for recipe in recipes:
recipe = Recipe.get_recipe(recipe, ctx)
if any([conflict in possible_dependencies
for conflict in recipe.conflicts]):
ok = False
break
if ok:
acceptable_bootstraps.append(bs)
info('Found {} acceptable bootstraps: {}'.format(
len(acceptable_bootstraps),
[bs.name for bs in acceptable_bootstraps]))
Expand Down Expand Up @@ -264,3 +266,20 @@ def fry_eggs(self, sitepackages):
if files:
shprint(sh.mv, '-t', sitepackages, *files)
shprint(sh.rm, '-rf', d)


def expand_dependencies(recipes):
recipe_lists = [[]]
for recipe in recipes:
if isinstance(recipe, (tuple, list)):
new_recipe_lists = []
for alternative in recipe:
for old_list in recipe_lists:
new_list = [i for i in old_list]
new_list.append(alternative)
new_recipe_lists.append(new_list)
recipe_lists = new_recipe_lists
else:
for old_list in recipe_lists:
old_list.append(recipe)
return recipe_lists
7 changes: 5 additions & 2 deletions pythonforandroid/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ def _add(self, graph, dependent, dependency):

def conflicts(self, conflict):
graphs = self.graphs
initial_num = len(graphs)
for i in range(len(graphs)):
graph = graphs[len(graphs) - 1 - i]
graph = graphs[initial_num - 1 - i]
if conflict in graph:
graphs.pop(len(graphs) - 1 - i)
graphs.pop(initial_num - 1 - i)
return len(graphs) == 0

def remove_remaining_conflicts(self, ctx):
Expand Down Expand Up @@ -227,6 +228,8 @@ def get_recipe_order_and_bootstrap(ctx, names, bs=None):
recipe_loaded.append(name)
graph.remove_remaining_conflicts(ctx)
build_order = list(graph.find_order(0))
build_order, python_modules, bs = get_recipe_order_and_bootstrap(
ctx, build_order + python_modules, bs)
return build_order, python_modules, bs

# Do a final check that the new bs doesn't pull in any conflicts
2 changes: 0 additions & 2 deletions pythonforandroid/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,5 +217,3 @@ def printtail(out, name, forecolor, tail_n=0,

return output


from pythonforandroid.util import unistr
9 changes: 6 additions & 3 deletions pythonforandroid/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,9 +580,12 @@ def has_libs(self, arch, *libs):

@classmethod
def recipe_dirs(cls, ctx):
return [ctx.local_recipes,
join(ctx.storage_dir, 'recipes'),
join(ctx.root_dir, "recipes")]
recipe_dirs = []
if ctx.local_recipes is not None:
recipe_dirs.append(ctx.local_recipes)
recipe_dirs.extend([join(ctx.storage_dir, 'recipes'),
join(ctx.root_dir, "recipes")])
return recipe_dirs

@classmethod
def list_recipes(cls, ctx):
Expand Down
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
40 changes: 40 additions & 0 deletions tests/test_graph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

from pythonforandroid.build import Context
from pythonforandroid.graph import get_recipe_order_and_bootstrap
from pythonforandroid.bootstrap import Bootstrap
from itertools import product

import pytest


ctx = Context()

name_sets = [['python2'],
['kivy']]
bootstraps = [None,
Bootstrap.get_bootstrap('pygame', ctx),
Bootstrap.get_bootstrap('sdl2', ctx)]
valid_combinations = list(product(name_sets, bootstraps))
valid_combinations.extend(
[(['python3crystax'], Bootstrap.get_bootstrap('sdl2', ctx)),
(['kivy', 'python3crystax'], Bootstrap.get_bootstrap('sdl2', ctx))])

@pytest.mark.parametrize('names,bootstrap', valid_combinations)
def test_valid_recipe_order_and_bootstrap(names, bootstrap):
get_recipe_order_and_bootstrap(ctx, names, bootstrap)

invalid_combinations = [[['python2', 'python3crystax'], None],
[['python3'], Bootstrap.get_bootstrap('pygame', ctx)]]

@pytest.mark.parametrize('names,bootstrap', invalid_combinations)
def test_invalid_recipe_order_and_bootstrap(names, bootstrap):
with pytest.raises(SystemExit):
get_recipe_order_and_bootstrap(ctx, names, bootstrap)

def test_bootstrap_dependency_addition():
build_order, python_modules, bs = get_recipe_order_and_bootstrap(
ctx, ['kivy'], None)
assert (('hostpython2' in build_order) or ('hostpython3' in build_order))

if __name__ == "__main__":
get_recipe_order_and_bootstrap(ctx, ['python3'], Bootstrap.get_bootstrap('sdl2', ctx))