lbry-android-sdk/p4a/ci/rebuild_updated_recipes.py
2022-11-29 15:35:24 -05:00

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()