Skip to content

add custom recipe support [needs py3 testing] #537

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 3 commits into from
Dec 19, 2015
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
2 changes: 2 additions & 0 deletions pythonforandroid/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
65 changes: 51 additions & 14 deletions pythonforandroid/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -13,6 +15,27 @@
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


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
Expand Down Expand Up @@ -512,15 +535,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):
Expand All @@ -529,17 +559,24 @@ 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
cls.recipes[name] = recipe
return recipe


Expand Down
24 changes: 16 additions & 8 deletions pythonforandroid/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:])
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)

Expand All @@ -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:
Expand Down