111 lines
3.7 KiB
Python
Executable file
111 lines
3.7 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Continuous Integration helper script.
|
|
Automatically detects recipes modified in a changeset (compares with master)
|
|
and recompiles them.
|
|
|
|
To run locally, set the environment variables before running:
|
|
```
|
|
ANDROID_SDK_HOME=~/.buildozer/android/platform/android-sdk-20
|
|
ANDROID_NDK_HOME=~/.buildozer/android/platform/android-ndk-r9c
|
|
./ci/rebuild_update_recipes.py
|
|
```
|
|
|
|
Current limitations:
|
|
- will fail on conflicting requirements
|
|
e.g. https://travis-ci.org/AndreMiras/python-for-android/builds/438840800
|
|
the list of recipes was huge and result was:
|
|
[ERROR]: Didn't find any valid dependency graphs.
|
|
[ERROR]: This means that some of your requirements pull in conflicting dependencies.
|
|
- only rebuilds on sdl2 bootstrap
|
|
"""
|
|
import sh
|
|
import os
|
|
import sys
|
|
import argparse
|
|
from pythonforandroid.build import Context
|
|
from pythonforandroid import logger
|
|
from pythonforandroid.toolchain import current_directory
|
|
from pythonforandroid.recipe import Recipe
|
|
from ci.constants import TargetPython, CORE_RECIPES, BROKEN_RECIPES
|
|
|
|
|
|
def modified_recipes(branch='origin/develop'):
|
|
"""
|
|
Returns a set of modified recipes between the current branch and the one
|
|
in param.
|
|
"""
|
|
# using the contrib version on purpose rather than sh.git, since it comes
|
|
# with a bunch of fixes, e.g. disabled TTY, see:
|
|
# https://stackoverflow.com/a/20128598/185510
|
|
git_diff = sh.contrib.git.diff('--name-only', branch)
|
|
recipes = set()
|
|
for file_path in git_diff:
|
|
if 'pythonforandroid/recipes/' in file_path:
|
|
recipe = file_path.split('/')[2]
|
|
recipes.add(recipe)
|
|
return recipes
|
|
|
|
|
|
def build(target_python, requirements, archs):
|
|
"""
|
|
Builds an APK given a target Python and a set of requirements.
|
|
"""
|
|
if not requirements:
|
|
return
|
|
android_sdk_home = os.environ['ANDROID_SDK_HOME']
|
|
android_ndk_home = os.environ['ANDROID_NDK_HOME']
|
|
requirements.add(target_python.name)
|
|
requirements = ','.join(requirements)
|
|
logger.info('requirements: {}'.format(requirements))
|
|
|
|
with current_directory('testapps/on_device_unit_tests/'):
|
|
# iterates to stream the output
|
|
for line in sh.python(
|
|
'setup.py', 'apk', '--sdk-dir', android_sdk_home,
|
|
'--ndk-dir', android_ndk_home, '--requirements',
|
|
requirements, *[f"--arch={arch}" for arch in archs],
|
|
_err_to_out=True, _iter=True):
|
|
print(line)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser("rebuild_updated_recipes")
|
|
parser.add_argument(
|
|
"--arch",
|
|
help="The archs to build for during tests",
|
|
action="append",
|
|
default=[],
|
|
)
|
|
args, unknown = parser.parse_known_args(sys.argv[1:])
|
|
|
|
logger.info(f"Building updated recipes for the following archs: {args.arch}")
|
|
|
|
target_python = TargetPython.python3
|
|
recipes = modified_recipes()
|
|
logger.info('recipes modified: {}'.format(recipes))
|
|
recipes -= CORE_RECIPES
|
|
logger.info('recipes to build: {}'.format(recipes))
|
|
context = Context()
|
|
|
|
# removing the deleted recipes for the given target (if any)
|
|
for recipe_name in recipes.copy():
|
|
try:
|
|
Recipe.get_recipe(recipe_name, context)
|
|
except ValueError:
|
|
# recipe doesn't exist, so probably we remove it
|
|
recipes.remove(recipe_name)
|
|
logger.warning(
|
|
'removed {} from recipes because deleted'.format(recipe_name)
|
|
)
|
|
|
|
# removing the known broken recipe for the given target
|
|
broken_recipes = BROKEN_RECIPES[target_python]
|
|
recipes -= broken_recipes
|
|
logger.info('recipes to build (no broken): {}'.format(recipes))
|
|
build(target_python, recipes, args.arch)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|