From 60cd17a30790ba4bcad74a4f83f2b4e53a5cce83 Mon Sep 17 00:00:00 2001 From: Ryan Pessa Date: Mon, 14 Dec 2015 16:30:22 -0600 Subject: [PATCH 1/3] add custom recipe support --- pythonforandroid/build.py | 2 ++ pythonforandroid/recipe.py | 63 +++++++++++++++++++++++++++-------- pythonforandroid/toolchain.py | 24 ++++++++----- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/pythonforandroid/build.py b/pythonforandroid/build.py index a25b8ddcb0..2872be6392 100644 --- a/pythonforandroid/build.py +++ b/pythonforandroid/build.py @@ -411,6 +411,8 @@ def __init__(self): self.toolchain_prefix = None self.toolchain_version = None + self.local_recipes = None + # root of the toolchain self.setup_dirs() diff --git a/pythonforandroid/recipe.py b/pythonforandroid/recipe.py index 0b7e4207e1..e5a136ea5e 100644 --- a/pythonforandroid/recipe.py +++ b/pythonforandroid/recipe.py @@ -2,6 +2,8 @@ import importlib import zipfile import glob +from six import PY2 + import sh import shutil from os import listdir, unlink, environ, mkdir @@ -13,6 +15,26 @@ from pythonforandroid.logger import (logger, info, warning, shprint, info_main) from pythonforandroid.util import (urlretrieve, current_directory, ensure_dir) +import pythonforandroid.recipes + + +if PY2: + import imp + import_recipe = imp.load_source +else: + import importlib.util + if hasattr(importlib.util, 'module_from_spec'): + def import_recipe(module, filename): + spec = importlib.util.spec_from_file_location(module, filename) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + else: + from importlib.machinery import SourceFileLoader + + def import_recipe(module, filename): + return SourceFileLoader(module, filename).load_module() + class Recipe(object): url = None @@ -512,15 +534,22 @@ def clean_build(self, arch=None): 'did not exist').format(self.name)) @classmethod - def list_recipes(cls): + def recipe_dirs(cls, ctx): + return [ctx.local_recipes, + join(ctx.storage_dir, 'recipes'), + join(ctx.root_dir, "recipes")] + + @classmethod + def list_recipes(cls, ctx): forbidden_dirs = ('__pycache__', ) - recipes_dir = join(dirname(__file__), "recipes") - for name in listdir(recipes_dir): - if name in forbidden_dirs: - continue - fn = join(recipes_dir, name) - if isdir(fn): - yield name + for recipes_dir in cls.recipe_dirs(ctx): + if recipes_dir and exists(recipes_dir): + for name in listdir(recipes_dir): + if name in forbidden_dirs: + continue + fn = join(recipes_dir, name) + if isdir(fn): + yield name @classmethod def get_recipe(cls, name, ctx): @@ -529,16 +558,22 @@ def get_recipe(cls, name, ctx): cls.recipes = {} if name in cls.recipes: return cls.recipes[name] - recipe_dir = join(ctx.root_dir, 'recipes', name) - if not exists(recipe_dir): # AND: This will need modifying - # for user-supplied recipes + + recipe_file = None + for recipes_dir in cls.recipe_dirs(ctx): + recipe_file = join(recipes_dir, name, '__init__.py') + if exists(recipe_file): + break + recipe_file = None + + if not recipe_file: raise IOError('Recipe folder does not exist') - mod = importlib.import_module( - "pythonforandroid.recipes.{}".format(name)) + + mod = import_recipe('pythonforandroid.recipes.{}'.format(name), recipe_file) if len(logger.handlers) > 1: logger.removeHandler(logger.handlers[1]) recipe = mod.recipe - recipe.recipe_dir = recipe_dir + recipe.recipe_dir = dirname(recipe_file) recipe.ctx = ctx return recipe diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index f03dbfc0f3..bdf656fc36 100755 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -261,6 +261,11 @@ def __init__(self): description=('Whether the dist recipes must perfectly match ' 'those requested')) + parser.add_argument( + '--local-recipes', '--local_recipes', + dest='local_recipes', default='./p4a-recipes', + help='Directory to look for local recipes') + self._read_configuration() args, unknown = parser.parse_known_args(sys.argv[1:]) @@ -293,6 +298,9 @@ def __init__(self): print('Unrecognized command') parser.print_help() exit(1) + + self.ctx.local_recipes = args.local_recipes + getattr(self, args.command)(unknown) def _read_configuration(self): @@ -322,9 +330,9 @@ def recipes(self, args): help="Produce a compact list suitable for scripting") add_boolean_option( - parser, ["color"], - default=True, - description='Whether the output should be colored:') + parser, ["color"], + default=True, + description='Whether the output should be colored:') args = parser.parse_args(args) @@ -334,18 +342,18 @@ def recipes(self, args): Fore = Null_Fore Style = Null_Style + ctx = self.ctx if args.compact: - print(" ".join(list(Recipe.list_recipes()))) + print(" ".join(set(Recipe.list_recipes(ctx)))) else: - ctx = self.ctx - for name in sorted(Recipe.list_recipes()): + for name in sorted(Recipe.list_recipes(ctx)): recipe = Recipe.get_recipe(name, ctx) version = str(recipe.version) print('{Fore.BLUE}{Style.BRIGHT}{recipe.name:<12} ' '{Style.RESET_ALL}{Fore.LIGHTBLUE_EX}' '{version:<8}{Style.RESET_ALL}'.format( - recipe=recipe, Fore=Fore, Style=Style, - version=version)) + recipe=recipe, Fore=Fore, Style=Style, + version=version)) print(' {Fore.GREEN}depends: {recipe.depends}' '{Fore.RESET}'.format(recipe=recipe, Fore=Fore)) if recipe.conflicts: From 6346bc14797d42dffba00d8eddb93f103454a405 Mon Sep 17 00:00:00 2001 From: Ryan Pessa Date: Mon, 14 Dec 2015 16:38:09 -0600 Subject: [PATCH 2/3] add note to unused import --- pythonforandroid/recipe.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pythonforandroid/recipe.py b/pythonforandroid/recipe.py index e5a136ea5e..eee6c829bc 100644 --- a/pythonforandroid/recipe.py +++ b/pythonforandroid/recipe.py @@ -15,6 +15,7 @@ from pythonforandroid.logger import (logger, info, warning, shprint, info_main) from pythonforandroid.util import (urlretrieve, current_directory, ensure_dir) +# this import is necessary to keep imp.load_source from complaining :) import pythonforandroid.recipes From 0e62ee64237608baf6797e181d00562b2ecb5b91 Mon Sep 17 00:00:00 2001 From: Ryan Pessa Date: Mon, 14 Dec 2015 17:17:27 -0600 Subject: [PATCH 3/3] add recipe to dict to prevent multiple imports --- pythonforandroid/recipe.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pythonforandroid/recipe.py b/pythonforandroid/recipe.py index eee6c829bc..6d08874cff 100644 --- a/pythonforandroid/recipe.py +++ b/pythonforandroid/recipe.py @@ -576,6 +576,7 @@ def get_recipe(cls, name, ctx): recipe = mod.recipe recipe.recipe_dir = dirname(recipe_file) recipe.ctx = ctx + cls.recipes[name] = recipe return recipe