From ee27da56f862946c1c5422c296df26fb756a40ef Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 00:14:45 +0100 Subject: [PATCH 01/12] Moved most command handling to single argparse --- pythonforandroid/toolchain.py | 578 +++++++++++++++++++++++++++------- 1 file changed, 457 insertions(+), 121 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 70405df1b8..ccb2635192 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -86,11 +86,10 @@ def wrapper_func(self, args): user_android_api=self.android_api, user_ndk_ver=self.ndk_version) dist = self._dist - dist_args, args = parse_dist_args(args) if dist.needs_build: info_notify('No dist exists that meets your requirements, ' 'so one will be built.') - build_dist_from_args(ctx, dist, dist_args) + build_dist_from_args(ctx, dist, args) func(self, args) return wrapper_func @@ -103,7 +102,7 @@ def dist_from_args(ctx, dist_args): ctx, name=dist_args.dist_name, recipes=split_argument_list(dist_args.requirements), - allow_download=dist_args.allow_download, + allow_download=False, # TODO: remove allow_build=dist_args.allow_build, extra_dist_dirs=split_argument_list(dist_args.extra_dist_dirs), require_perfect_match=dist_args.require_perfect_match) @@ -144,154 +143,528 @@ def build_dist_from_args(ctx, dist, args): .format(join(ctx.dist_dir, ctx.dist_name))) -def parse_dist_args(args_list): - parser = argparse.ArgumentParser( - description='Create a newAndroid project') - parser.add_argument( - '--bootstrap', - help=('The name of the bootstrap type, \'pygame\' ' - 'or \'sdl2\', or leave empty to let a ' - 'bootstrap be chosen automatically from your ' - 'requirements.'), - default=None) - args, unknown = parser.parse_known_args(args_list) - return args, unknown - - def split_argument_list(l): if not len(l): return [] return re.split(r'[ ,]+', l) +# class NewToolchainCL(object): +# def __init__(self): +# parser = argparse.ArgumentParser( +# description=('A packaging tool for turning Python scripts and apps ' +# 'into Android APKs')) + +# parser.add_argument( +# '--debug', dest='debug', action='store_true', +# help='Display debug output and all build info') +# parser.add_argument( +# '--color', dest='color', choices=['always', 'never', 'auto'], +# help='Enable or disable color output (default enabled on tty)') +# parser.add_argument( +# '--sdk-dir', '--sdk_dir', dest='sdk_dir', default='', +# help='The filepath where the Android SDK is installed') +# parser.add_argument( +# '--ndk-dir', '--ndk_dir', dest='ndk_dir', default='', +# help='The filepath where the Android NDK is installed') +# parser.add_argument( +# '--android-api', '--android_api', dest='android_api', default=0, type=int, +# help='The Android API level to build against.') +# parser.add_argument( +# '--ndk-version', '--ndk_version', dest='ndk_version', default='', +# help=('The version of the Android NDK. This is optional, ' +# 'we try to work it out automatically from the ndk_dir.')) + +# default_storage_dir = user_data_dir('python-for-android') +# if ' ' in default_storage_dir: +# default_storage_dir = '~/.python-for-android' +# parser.add_argument( +# '--storage-dir', dest='storage_dir', +# default=default_storage_dir, +# help=('Primary storage directory for downloads and builds ' +# '(default: {})'.format(default_storage_dir))) + +# # AND: This option doesn't really fit in the other categories, the +# # arg structure needs a rethink +# parser.add_argument( +# '--arch', +# help='The archs to build for, separated by commas.', +# default='armeabi') + +# # Options for specifying the Distribution +# parser.add_argument( +# '--dist-name', '--dist_name', +# help='The name of the distribution to use or create', +# default='') + +# parser.add_argument( +# '--requirements', +# help=('Dependencies of your app, should be recipe names or ' +# 'Python modules'), +# default='') + +# parser.add_argument( +# '--bootstrap', +# help='The bootstrap to build with. Leave unset to choose automatically.', +# default=None) + +# add_boolean_option( +# parser, ["allow-download"], +# default=False, +# description='Whether to allow binary dist download:') + +# add_boolean_option( +# parser, ["allow-build"], +# default=True, +# description='Whether to allow compilation of a new distribution:') + +# add_boolean_option( +# parser, ["force-build"], +# default=False, +# description='Whether to force compilation of a new distribution:') + +# parser.add_argument( +# '--extra-dist-dirs', '--extra_dist_dirs', +# dest='extra_dist_dirs', default='', +# help='Directories in which to look for distributions') + +# add_boolean_option( +# parser, ["require-perfect-match"], +# default=False, +# 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') + +# add_boolean_option( +# parser, ['copy-libs'], +# default=False, +# description='Copy libraries instead of using biglink (Android 4.3+)') + + +# subparsers = parser.add_subparsers(dest='subparser_name', +# help='The command to run') + +# parser_recipes = subparsers.add_parser( +# 'recipes', help='List the available recipes') +# parser_recipes.add_argument( +# "--compact", action="store_true", default=False, +# help="Produce a compact list suitable for scripting") + +# parser_bootstraps = subparsers.add_parser( +# 'bootstraps', help='List the available bootstraps') +# parser_clean_all = subparsers.add_parser( +# 'clean_all', aliases=['clean-all'], +# help='Delete all builds, dists and caches') +# parser_clean_dists = subparsers.add_parser( +# 'clean_dists', aliases=['clean-dists'], +# help='Delete all dists') +# parser_clean_bootstrap_builds = subparsers.add_parser( +# 'clean_bootstrap_builds', aliases=['clean-bootstrap-builds'], +# help='Delete all bootstrap builds') +# parser_clean_builds = subparsers.add_parser( +# 'clean_builds', aliases=['clean-builds'], +# help='Delete all builds') + +# parser_clean_recipe_build = subparsers.add_parser( +# 'clean_recipe_build', aliases=['clean-recipe-build'], +# help='Delete the build info for the given recipe') +# parser_clean_recipe_build.add_argument('recipe', help='The recipe name') + +# parser_clear_download_cache= subparsers.add_parser( +# 'clear_download_cache', aliases=['clear-download-cache'], +# help='Delete any cached recipe downloads') +# parser_export_dist = subparsers.add_parser( +# 'export_dist', aliases=['export-dist'], +# help='Copy the named dist to the given path') +# parser_symlink_dist = subparsers.add_parser( +# 'symlink_dist', aliases=['symlink-dist'], +# help='Symlink the named dist at the given path') +# # todo: make symlink an option of export +# parser_apk = subparsers.add_parser( +# 'apk', help='Build an APK') +# parser_create = subparsers.add_parser( +# 'create', help='Compile a set of requirements into a dist') +# parser_context_info = subparsers.add_parser( +# 'context_info', aliases=['context-info'], +# help='Print some debug information about the build context') +# parser_archs = subparsers.add_parser( +# 'archs', help='List the available target architectures') +# parser_distributions = subparsers.add_parser( +# 'distributions', aliases=['dists'], +# help='List the currently available (compiled) dists') +# parser_delete_dist = subparsers.add_parser( +# 'delete_dist', aliases=['delete-dist'], help='Delete a compiled dist') + +# parser_sdk_tools = subparsers.add_parser( +# 'sdk_tools', aliases=['sdk-tools'], +# help='Run the given binary from the SDK tools dis') +# parser_sdk_tools.add_argument('tool', help=('The tool binary name to run')) + +# parser_adb = subparsers.add_parser( +# 'adb', help='Run adb from the given SDK') +# parser_logcat = subparsers.add_parser( +# 'logcat', help='Run logcat from the given SDK') +# parser_build_status = subparsers.add_parser( +# 'build_status', aliases=['build-status'], +# help='Print some debug information about current built components') + +# parser_distributions.set_defaults(func=self.distributions) + +# print('ready to parse') +# args = parser.parse_args(sys.argv[1:]) +# print('parsed') + +# setup_color(args.color) + +# # strip version from requirements, and put them in environ +# requirements = [] +# for requirement in split_argument_list(args.requirements): +# if "==" in requirement: +# requirement, version = requirement.split(u"==", 1) +# os.environ["VERSION_{}".format(requirement)] = version +# info('Recipe {}: version "{}" requested'.format( +# requirement, version)) +# requirements.append(requirement) +# args.requirements = u",".join(requirements) + +# self.ctx = Context() +# self.storage_dir = args.storage_dir +# self.ctx.setup_dirs(self.storage_dir) +# self.sdk_dir = args.sdk_dir +# self.ndk_dir = args.ndk_dir +# self.android_api = args.android_api +# self.ndk_version = args.ndk_version + +# self._archs = split_argument_list(args.arch) + +# # AND: Fail nicely if the args aren't handled yet +# if args.extra_dist_dirs: +# warning('Received --extra_dist_dirs but this arg currently is not ' +# 'handled, exiting.') +# exit(1) + +# self.ctx.local_recipes = args.local_recipes +# self.ctx.copy_libs = args.copy_libs + +# # Each subparser corresponds to a method +# getattr(self, args.subparser_name.replace('-', '_'))(args) + +# def dists(self, args): +# print('args', args) +# self.distributions(args) + +# def distributions(self, args): +# '''Lists all distributions currently available (i.e. that have already +# been built).''' +# ctx = self.ctx +# dists = Distribution.get_distributions(ctx) + +# if dists: +# print('{Style.BRIGHT}Distributions currently installed are:' +# '{Style.RESET_ALL}'.format(Style=Out_Style, Fore=Out_Fore)) +# pretty_log_dists(dists, print) +# else: +# print('{Style.BRIGHT}There are no dists currently built.' +# '{Style.RESET_ALL}'.format(Style=Out_Style)) + +# def context_info(self, args): +# '''Prints some debug information about which system paths +# python-for-android will internally use for package building, along +# with information about where the Android SDK and NDK will be called +# from.''' +# ctx = self.ctx +# for attribute in ('root_dir', 'build_dir', 'dist_dir', 'libs_dir', +# 'eccache', 'cython', 'sdk_dir', 'ndk_dir', +# 'ndk_platform', 'ndk_ver', 'android_api'): +# print('{} is {}'.format(attribute, getattr(ctx, attribute))) + +# def archs(self, args): +# '''List the target architectures available to be built for.''' +# print('{Style.BRIGHT}Available target architectures are:' +# '{Style.RESET_ALL}'.format(Style=Out_Style)) +# for arch in self.ctx.archs: +# print(' {}'.format(arch.arch)) + +# def delete_dist(self, args): +# dist = self._dist +# if dist.needs_build: +# info('No dist exists that matches your specifications, ' +# 'exiting without deleting.') +# shutil.rmtree(dist.dist_dir) + +# def sdk_tools(self, args): +# '''Runs the android binary from the detected SDK directory, passing +# all arguments straight to it. This binary is used to install +# e.g. platform-tools for different API level targets. This is +# intended as a convenience function if android is not in your +# $PATH. +# ''' +# ctx = self.ctx +# ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, +# user_ndk_dir=self.ndk_dir, +# user_android_api=self.android_api, +# user_ndk_ver=self.ndk_version) +# android = sh.Command(join(ctx.sdk_dir, 'tools', args.tool)) +# output = android( +# *unknown, _iter=True, _out_bufsize=1, _err_to_out=True) +# for line in output: +# sys.stdout.write(line) +# sys.stdout.flush() + +# def adb(self, args): +# '''Runs the adb binary from the detected SDK directory, passing all +# arguments straight to it. This is intended as a convenience +# function if adb is not in your $PATH. +# ''' +# ctx = self.ctx +# ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, +# user_ndk_dir=self.ndk_dir, +# user_android_api=self.android_api, +# user_ndk_ver=self.ndk_version) +# if platform in ('win32', 'cygwin'): +# adb = sh.Command(join(ctx.sdk_dir, 'platform-tools', 'adb.exe')) +# else: +# adb = sh.Command(join(ctx.sdk_dir, 'platform-tools', 'adb')) +# info_notify('Starting adb...') +# output = adb(args, _iter=True, _out_bufsize=1, _err_to_out=True) +# for line in output: +# sys.stdout.write(line) +# sys.stdout.flush() + +# def logcat(self, args): +# '''Runs ``adb logcat`` using the adb binary from the detected SDK +# directory. All extra args are passed as arguments to logcat.''' +# self.adb(['logcat'] + args) + + +# def build_status(self, args): + +# print('{Style.BRIGHT}Bootstraps whose core components are probably ' +# 'already built:{Style.RESET_ALL}'.format(Style=Out_Style)) +# for filen in os.listdir(join(self.ctx.build_dir, 'bootstrap_builds')): +# print(' {Fore.GREEN}{Style.BRIGHT}{filen}{Style.RESET_ALL}' +# .format(filen=filen, Fore=Out_Fore, Style=Out_Style)) + +# print('{Style.BRIGHT}Recipes that are probably already built:' +# '{Style.RESET_ALL}'.format(Style=Out_Style)) +# if exists(join(self.ctx.build_dir, 'other_builds')): +# for filen in sorted( +# os.listdir(join(self.ctx.build_dir, 'other_builds'))): +# name = filen.split('-')[0] +# dependencies = filen.split('-')[1:] +# recipe_str = (' {Style.BRIGHT}{Fore.GREEN}{name}' +# '{Style.RESET_ALL}'.format( +# Style=Out_Style, name=name, Fore=Out_Fore)) +# if dependencies: +# recipe_str += ( +# ' ({Fore.BLUE}with ' + ', '.join(dependencies) + +# '{Fore.RESET})').format(Fore=Out_Fore) +# recipe_str += '{Style.RESET_ALL}'.format(Style=Out_Style) +# print(recipe_str) + + class ToolchainCL(object): def __init__(self): parser = argparse.ArgumentParser( - description="Tool for managing the Android / Python toolchain", - usage="""toolchain [] - -Available commands: -adb Runs adb binary from the detected SDK dir -apk Create an APK using the given distribution -bootstraps List all the bootstraps available to build with. -build_status Informations about the current build -create Build an android project with all recipes -clean_all Delete all build components -clean_builds Delete all build caches -clean_dists Delete all compiled distributions -clean_bootstrap_builds Delete all compiled bootstraps -clean_download_cache Delete any downloaded recipe packages -clean_recipe_build Delete the build files of a recipe -distributions List all distributions -export_dist Copies a created dist to an output directory -logcat Runs logcat from the detected SDK dir -print_context_info Prints debug informations -recipes List all the available recipes -sdk_tools Runs android binary from the detected SDK dir -symlink_dist Symlinks a created dist to an output directory - -Planned commands: -build_dist -""") - parser.add_argument("command", help="Command to run") - - # General options - parser.add_argument( + description=('A packaging tool for turning Python scripts and apps ' + 'into Android APKs')) + + generic_parser = argparse.ArgumentParser( + add_help=False, + description=('Generic arguments applied to all commands')) + dist_parser = argparse.ArgumentParser( + add_help=False, + description=('Arguments for dist building')) + + generic_parser.add_argument( '--debug', dest='debug', action='store_true', + default=False, help='Display debug output and all build info') - parser.add_argument( + generic_parser.add_argument( '--color', dest='color', choices=['always', 'never', 'auto'], help='Enable or disable color output (default enabled on tty)') - parser.add_argument( + generic_parser.add_argument( '--sdk-dir', '--sdk_dir', dest='sdk_dir', default='', help='The filepath where the Android SDK is installed') - parser.add_argument( + generic_parser.add_argument( '--ndk-dir', '--ndk_dir', dest='ndk_dir', default='', help='The filepath where the Android NDK is installed') - parser.add_argument( + generic_parser.add_argument( '--android-api', '--android_api', dest='android_api', default=0, type=int, help='The Android API level to build against.') - parser.add_argument( + generic_parser.add_argument( '--ndk-version', '--ndk_version', dest='ndk_version', default='', help=('The version of the Android NDK. This is optional, ' 'we try to work it out automatically from the ndk_dir.')) - parser.add_argument( + + default_storage_dir = user_data_dir('python-for-android') + if ' ' in default_storage_dir: + default_storage_dir = '~/.python-for-android' + generic_parser.add_argument( '--storage-dir', dest='storage_dir', - default=self.default_storage_dir, + default=default_storage_dir, help=('Primary storage directory for downloads and builds ' - '(default: {})'.format(self.default_storage_dir))) + '(default: {})'.format(default_storage_dir))) # AND: This option doesn't really fit in the other categories, the # arg structure needs a rethink - parser.add_argument( + generic_parser.add_argument( '--arch', help='The archs to build for, separated by commas.', default='armeabi') # Options for specifying the Distribution - parser.add_argument( + generic_parser.add_argument( '--dist-name', '--dist_name', help='The name of the distribution to use or create', default='') - parser.add_argument( + + generic_parser.add_argument( '--requirements', help=('Dependencies of your app, should be recipe names or ' 'Python modules'), default='') + + generic_parser.add_argument( + '--bootstrap', + help='The bootstrap to build with. Leave unset to choose automatically.', + default=None) add_boolean_option( - parser, ["allow-download"], + generic_parser, ["allow-download"], default=False, description='Whether to allow binary dist download:') add_boolean_option( - parser, ["allow-build"], + generic_parser, ["allow-build"], default=True, description='Whether to allow compilation of a new distribution:') add_boolean_option( - parser, ["force-build"], + generic_parser, ["force-build"], default=False, description='Whether to force compilation of a new distribution:') - parser.add_argument( + generic_parser.add_argument( '--extra-dist-dirs', '--extra_dist_dirs', dest='extra_dist_dirs', default='', help='Directories in which to look for distributions') add_boolean_option( - parser, ["require-perfect-match"], + generic_parser, ["require-perfect-match"], default=False, description=('Whether the dist recipes must perfectly match ' 'those requested')) - parser.add_argument( + generic_parser.add_argument( '--local-recipes', '--local_recipes', dest='local_recipes', default='./p4a-recipes', help='Directory to look for local recipes') add_boolean_option( - parser, ['copy-libs'], + generic_parser, ['copy-libs'], default=False, description='Copy libraries instead of using biglink (Android 4.3+)') - self._read_configuration() + subparsers = parser.add_subparsers(dest='subparser_name', + help='The command to run') - args, unknown = parser.parse_known_args(sys.argv[1:]) - self.dist_args = args + parser_recipes = subparsers.add_parser( + 'recipes', + parents=[generic_parser], + help='List the available recipes') + parser_recipes.add_argument( + "--compact", action="store_true", default=False, + help="Produce a compact list suitable for scripting") - setup_color(args.color) + parser_bootstraps = subparsers.add_parser( + 'bootstraps', help='List the available bootstraps', + parents=[generic_parser]) + parser_clean_all = subparsers.add_parser( + 'clean_all', aliases=['clean-all'], + help='Delete all builds, dists and caches', + parents=[generic_parser]) + parser_clean_dists = subparsers.add_parser( + 'clean_dists', aliases=['clean-dists'], + help='Delete all dists', + parents=[generic_parser]) + parser_clean_bootstrap_builds = subparsers.add_parser( + 'clean_bootstrap_builds', aliases=['clean-bootstrap-builds'], + help='Delete all bootstrap builds', + parents=[generic_parser]) + parser_clean_builds = subparsers.add_parser( + 'clean_builds', aliases=['clean-builds'], + help='Delete all builds', + parents=[generic_parser]) + + parser_clean_recipe_build = subparsers.add_parser( + 'clean_recipe_build', aliases=['clean-recipe-build'], + help='Delete the build info for the given recipe', + parents=[generic_parser]) + parser_clean_recipe_build.add_argument('recipe', help='The recipe name') + + parser_clear_download_cache= subparsers.add_parser( + 'clear_download_cache', aliases=['clear-download-cache'], + help='Delete any cached recipe downloads', + parents=[generic_parser]) + parser_export_dist = subparsers.add_parser( + 'export_dist', aliases=['export-dist'], + help='Copy the named dist to the given path', + parents=[generic_parser]) + parser_symlink_dist = subparsers.add_parser( + 'symlink_dist', aliases=['symlink-dist'], + help='Symlink the named dist at the given path', + parents=[generic_parser]) + # todo: make symlink an option of export + parser_apk = subparsers.add_parser( + 'apk', help='Build an APK', + parents=[generic_parser]) + parser_create = subparsers.add_parser( + 'create', help='Compile a set of requirements into a dist', + parents=[generic_parser]) + parser_context_info = subparsers.add_parser( + 'context_info', aliases=['context-info'], + help='Print some debug information about the build context', + parents=[generic_parser]) + parser_archs = subparsers.add_parser( + 'archs', help='List the available target architectures', + parents=[generic_parser]) + parser_distributions = subparsers.add_parser( + 'distributions', aliases=['dists'], + help='List the currently available (compiled) dists', + parents=[generic_parser]) + parser_delete_dist = subparsers.add_parser( + 'delete_dist', aliases=['delete-dist'], help='Delete a compiled dist', + parents=[generic_parser]) + + parser_sdk_tools = subparsers.add_parser( + 'sdk_tools', aliases=['sdk-tools'], + help='Run the given binary from the SDK tools dis', + parents=[generic_parser]) + parser_sdk_tools.add_argument( + 'tool', help=('The tool binary name to run')) + + parser_adb = subparsers.add_parser( + 'adb', help='Run adb from the given SDK', + parents=[generic_parser]) + parser_logcat = subparsers.add_parser( + 'logcat', help='Run logcat from the given SDK', + parents=[generic_parser]) + parser_build_status = subparsers.add_parser( + 'build_status', aliases=['build-status'], + help='Print some debug information about current built components', + parents=[generic_parser]) + + print('ready to parse', sys.argv[1:]) + args = parser.parse_args(sys.argv[1:]) + print('args are', args) - info(''.join( - [Err_Style.BRIGHT, Err_Fore.RED, - 'This python-for-android revamp is an experimental alpha release!', - Err_Style.RESET_ALL])) - info(''.join( - [Err_Fore.RED, - ('It should work (mostly), but you may experience ' - 'missing features or bugs.'), - Err_Style.RESET_ALL])) + setup_color(args.color) # strip version from requirements, and put them in environ requirements = [] @@ -304,9 +677,6 @@ def __init__(self): requirements.append(requirement) args.requirements = u",".join(requirements) - if args.debug: - logger.setLevel(logging.DEBUG) - self.ctx = Context() self.storage_dir = args.storage_dir self.ctx.setup_dirs(self.storage_dir) @@ -322,26 +692,12 @@ def __init__(self): warning('Received --extra_dist_dirs but this arg currently is not ' 'handled, exiting.') exit(1) - if args.allow_download: - warning('Received --allow_download but this arg currently is not ' - 'handled, exiting.') - exit(1) - # if args.allow_build: - # warning('Received --allow_build but this arg currently is not ' - # 'handled, exiting.') - # exit(1) - - command_method_name = args.command.replace('-', '_') - - if not hasattr(self, command_method_name): - print('Unrecognized command') - parser.print_help() - exit(1) self.ctx.local_recipes = args.local_recipes self.ctx.copy_libs = args.copy_libs - getattr(self, command_method_name)(unknown) + # Each subparser corresponds to a method + getattr(self, args.subparser_name.replace('-', '_'))(args) @property def default_storage_dir(self): @@ -364,14 +720,6 @@ def _read_configuration(self): sys.argv.append(arg) def recipes(self, args): - parser = argparse.ArgumentParser( - description="List all the available recipes") - parser.add_argument( - "--compact", action="store_true", default=False, - help="Produce a compact list suitable for scripting") - - args = parser.parse_args(args) - ctx = self.ctx if args.compact: print(" ".join(set(Recipe.list_recipes(ctx)))) @@ -407,9 +755,6 @@ def bootstraps(self, args): def clean_all(self, args): '''Delete all build components; the package cache, package builds, bootstrap builds and distributions.''' - parser = argparse.ArgumentParser( - description="Clean the build cache, downloads and dists") - parsed_args = parser.parse_args(args) self.clean_dists(args) self.clean_builds(args) self.clean_download_cache(args) @@ -417,9 +762,6 @@ def clean_all(self, args): def clean_dists(self, args): '''Delete all compiled distributions in the internal distribution directory.''' - parser = argparse.ArgumentParser( - description="Delete any distributions that have been built.") - args = parser.parse_args(args) ctx = self.ctx if exists(ctx.dist_dir): shutil.rmtree(ctx.dist_dir) @@ -440,9 +782,6 @@ def clean_builds(self, args): distributions. You can also use clean_recipe_build to delete the build of a specific recipe. ''' - parser = argparse.ArgumentParser( - description="Delete all build files (but not download caches)") - args = parser.parse_args(args) ctx = self.ctx # if exists(ctx.dist_dir): # shutil.rmtree(ctx.dist_dir) @@ -463,11 +802,6 @@ def clean_recipe_build(self, args): clean_builds, or attempt to clean other recipes until things work again. ''' - parser = argparse.ArgumentParser( - description="Delete all build files for the given recipe name.") - parser.add_argument('recipe', help='The recipe name') - args = parser.parse_args(args) - recipe = Recipe.get_recipe(args.recipe, self.ctx) info('Cleaning build for {} recipe.'.format(recipe.name)) recipe.clean_build() @@ -546,6 +880,7 @@ def _dist(self): def apk(self, args): '''Create an APK using the given distribution.''' + print('got to apk function') ap = argparse.ArgumentParser( description='Build an APK') ap.add_argument('--release', dest='build_mode', action='store_const', @@ -641,7 +976,7 @@ def create(self, args): # build_dist_from_args(ctx, dist, args) - def print_context_info(self, args): + def context_info(self, args): '''Prints some debug information about which system paths python-for-android will internally use for package building, along with information about where the Android SDK and NDK will be called @@ -761,6 +1096,7 @@ def build_status(self, args): def main(): ToolchainCL() + # NewToolchainCL() if __name__ == "__main__": - main() + new_main() From ded3211c8ccd5dda2d21fc88aca0e4b28533be14 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 00:20:07 +0100 Subject: [PATCH 02/12] Moved argparseing from methods to subparsers --- pythonforandroid/toolchain.py | 57 ++++++++++++----------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index ccb2635192..17b2b7d76f 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -612,18 +612,38 @@ def __init__(self): 'clear_download_cache', aliases=['clear-download-cache'], help='Delete any cached recipe downloads', parents=[generic_parser]) + parser_export_dist = subparsers.add_parser( 'export_dist', aliases=['export-dist'], help='Copy the named dist to the given path', parents=[generic_parser]) + parser_export_dist.add_argument('--output', help=('The output dir to copy to'), + required=True) + parser_symlink_dist = subparsers.add_parser( 'symlink_dist', aliases=['symlink-dist'], help='Symlink the named dist at the given path', parents=[generic_parser]) + parser_symlink_dist.add_argument('--output', help=('The output dir to copy to'), + required=True) # todo: make symlink an option of export + parser_apk = subparsers.add_parser( 'apk', help='Build an APK', parents=[generic_parser]) + parser_apk.add_argument('--release', dest='build_mode', action='store_const', + const='release', default='debug', + help='Build the PARSER_APK. in Release mode') + parser_apk.add_argument('--keystore', dest='keystore', action='store', default=None, + help=('Keystore for JAR signing key, will use jarsigner ' + 'default if not specified (release build only)')) + parser_apk.add_argument('--signkey', dest='signkey', action='store', default=None, + help='Key alias to sign PARSER_APK. with (release build only)') + parser_apk.add_argument('--keystorepw', dest='keystorepw', action='store', default=None, + help='Password for keystore') + parser_apk.add_argument('--signkeypw', dest='signkeypw', action='store', default=None, + help='Password for key alias') + parser_create = subparsers.add_parser( 'create', help='Compile a set of requirements into a dist', parents=[generic_parser]) @@ -812,9 +832,6 @@ def clean_download_cache(self, args): This does *not* delete the build caches or final distributions. ''' - parser = argparse.ArgumentParser( - description="Delete all download caches") - args = parser.parse_args(args) ctx = self.ctx if exists(ctx.packages_path): shutil.rmtree(ctx.packages_path) @@ -827,12 +844,6 @@ def export_dist(self, args): or call build.py, though you do not in general need to do this and can use the apk command instead. ''' - parser = argparse.ArgumentParser( - description='Copy a created dist to a given directory') - parser.add_argument('--output', help=('The output dir to copy to'), - required=True) - args = parser.parse_args(args) - ctx = self.ctx dist = dist_from_args(ctx, self.dist_args) if dist.needs_build: @@ -851,12 +862,6 @@ def symlink_dist(self, args): and can use the apk command instead. ''' - parser = argparse.ArgumentParser( - description='Symlink a created dist to a given directory') - parser.add_argument('--output', help=('The output dir to copy to'), - required=True) - args = parser.parse_args(args) - ctx = self.ctx dist = dist_from_args(ctx, self.dist_args) if dist.needs_build: @@ -880,23 +885,6 @@ def _dist(self): def apk(self, args): '''Create an APK using the given distribution.''' - print('got to apk function') - ap = argparse.ArgumentParser( - description='Build an APK') - ap.add_argument('--release', dest='build_mode', action='store_const', - const='release', default='debug', - help='Build the APK in Release mode') - ap.add_argument('--keystore', dest='keystore', action='store', default=None, - help=('Keystore for JAR signing key, will use jarsigner ' - 'default if not specified (release build only)')) - ap.add_argument('--signkey', dest='signkey', action='store', default=None, - help='Key alias to sign APK with (release build only)') - ap.add_argument('--keystorepw', dest='keystorepw', action='store', default=None, - help='Password for keystore') - ap.add_argument('--signkeypw', dest='signkeypw', action='store', default=None, - help='Password for key alias') - apk_args, args = ap.parse_known_args(args) - ctx = self.ctx dist = self._dist @@ -1026,11 +1014,6 @@ def sdk_tools(self, args): intended as a convenience function if android is not in your $PATH. ''' - parser = argparse.ArgumentParser( - description='Run a binary from the /path/to/sdk/tools directory') - parser.add_argument('tool', help=('The tool binary name to run')) - args, unknown = parser.parse_known_args(args) - ctx = self.ctx ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, user_ndk_dir=self.ndk_dir, From 3319b445f9ce64a6f1f1a2c9ef28cd5e6a721341 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 00:47:49 +0100 Subject: [PATCH 03/12] Removed unused dist arguments --- pythonforandroid/distribution.py | 9 ++----- pythonforandroid/toolchain.py | 40 ++++++++++++-------------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/pythonforandroid/distribution.py b/pythonforandroid/distribution.py index 27fd3dac25..0db59a280f 100644 --- a/pythonforandroid/distribution.py +++ b/pythonforandroid/distribution.py @@ -41,9 +41,9 @@ def __repr__(self): return str(self) @classmethod - def get_distribution(cls, ctx, name=None, recipes=[], allow_download=True, + def get_distribution(cls, ctx, name=None, recipes=[], force_build=False, - allow_build=True, extra_dist_dirs=[], + extra_dist_dirs=[], require_perfect_match=False): '''Takes information about the distribution, and decides what kind of distribution it will be. @@ -59,11 +59,6 @@ def get_distribution(cls, ctx, name=None, recipes=[], allow_download=True, exists, it will be used. recipes : list The recipes that the distribution must contain. - allow_download : bool - Whether binary dists may be downloaded. - allow_build : bool - Whether the distribution may be built from scratch if necessary. - This is always False on e.g. Windows. force_download: bool If True, only downloaded dists are considered. force_build : bool diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 17b2b7d76f..e72b8a4792 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -102,8 +102,6 @@ def dist_from_args(ctx, dist_args): ctx, name=dist_args.dist_name, recipes=split_argument_list(dist_args.requirements), - allow_download=False, # TODO: remove - allow_build=dist_args.allow_build, extra_dist_dirs=split_argument_list(dist_args.extra_dist_dirs), require_perfect_match=dist_args.require_perfect_match) @@ -535,16 +533,6 @@ def __init__(self): help='The bootstrap to build with. Leave unset to choose automatically.', default=None) - add_boolean_option( - generic_parser, ["allow-download"], - default=False, - description='Whether to allow binary dist download:') - - add_boolean_option( - generic_parser, ["allow-build"], - default=True, - description='Whether to allow compilation of a new distribution:') - add_boolean_option( generic_parser, ["force-build"], default=False, @@ -681,21 +669,23 @@ def __init__(self): parents=[generic_parser]) print('ready to parse', sys.argv[1:]) - args = parser.parse_args(sys.argv[1:]) + args, unknown = parser.parse_known_args(sys.argv[1:]) + args.unknown_args = unknown print('args are', args) setup_color(args.color) # strip version from requirements, and put them in environ - requirements = [] - for requirement in split_argument_list(args.requirements): - if "==" in requirement: - requirement, version = requirement.split(u"==", 1) - os.environ["VERSION_{}".format(requirement)] = version - info('Recipe {}: version "{}" requested'.format( - requirement, version)) - requirements.append(requirement) - args.requirements = u",".join(requirements) + if hasattr(args, 'requirements'): + requirements = [] + for requirement in split_argument_list(args.requirements): + if "==" in requirement: + requirement, version = requirement.split(u"==", 1) + os.environ["VERSION_{}".format(requirement)] = version + info('Recipe {}: version "{}" requested'.format( + requirement, version)) + requirements.append(requirement) + args.requirements = u",".join(requirements) self.ctx = Context() self.storage_dir = args.storage_dir @@ -845,7 +835,7 @@ def export_dist(self, args): and can use the apk command instead. ''' ctx = self.ctx - dist = dist_from_args(ctx, self.dist_args) + dist = dist_from_args(ctx, args) if dist.needs_build: info('You asked to export a dist, but there is no dist ' 'with suitable recipes available. For now, you must ' @@ -918,7 +908,7 @@ def apk(self, args): build = imp.load_source('build', join(dist.dist_dir, 'build.py')) with current_directory(dist.dist_dir): - build_args = build.parse_args(args) + build_args = build.parse_args(args.unknown_args) output = shprint(sh.ant, apk_args.build_mode, _tail=20, _critical=True, _env=env) info_main('# Copying APK to current directory') @@ -1049,7 +1039,7 @@ def adb(self, args): def logcat(self, args): '''Runs ``adb logcat`` using the adb binary from the detected SDK directory. All extra args are passed as arguments to logcat.''' - self.adb(['logcat'] + args) + self.adb(['logcat'] + args.unknown_args) def build_status(self, args): From 9bf670179f4f3b6c67614bacb0208510f9a39737 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 00:51:41 +0100 Subject: [PATCH 04/12] Moved dist_args references to the main args object --- pythonforandroid/toolchain.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index e72b8a4792..8d1b3cf06c 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -94,16 +94,16 @@ def wrapper_func(self, args): return wrapper_func -def dist_from_args(ctx, dist_args): +def dist_from_args(ctx, args): '''Parses out any distribution-related arguments, and uses them to obtain a Distribution class instance for the build. ''' return Distribution.get_distribution( ctx, - name=dist_args.dist_name, - recipes=split_argument_list(dist_args.requirements), - extra_dist_dirs=split_argument_list(dist_args.extra_dist_dirs), - require_perfect_match=dist_args.require_perfect_match) + name=args.dist_name, + recipes=split_argument_list(args.requirements), + extra_dist_dirs=split_argument_list(args.extra_dist_dirs), + require_perfect_match=args.require_perfect_match) def build_dist_from_args(ctx, dist, args): @@ -668,10 +668,10 @@ def __init__(self): help='Print some debug information about current built components', parents=[generic_parser]) - print('ready to parse', sys.argv[1:]) args, unknown = parser.parse_known_args(sys.argv[1:]) args.unknown_args = unknown - print('args are', args) + + self.args = args setup_color(args.color) @@ -853,7 +853,7 @@ def symlink_dist(self, args): ''' ctx = self.ctx - dist = dist_from_args(ctx, self.dist_args) + dist = dist_from_args(ctx, args) if dist.needs_build: info('You asked to symlink a dist, but there is no dist ' 'with suitable recipes available. For now, you must ' @@ -863,12 +863,12 @@ def symlink_dist(self, args): # def _get_dist(self): # ctx = self.ctx - # dist = dist_from_args(ctx, self.dist_args) + # dist = dist_from_args(ctx, self.args) @property def _dist(self): ctx = self.ctx - dist = dist_from_args(ctx, self.dist_args) + dist = dist_from_args(ctx, self.args) return dist @require_prebuilt_dist @@ -942,7 +942,7 @@ def create(self, args): pass # The decorator does this for us # ctx = self.ctx - # dist = dist_from_args(ctx, self.dist_args) + # dist = dist_from_args(ctx, self.args) # if not dist.needs_build: # info('You asked to create a distribution, but a dist with ' # 'this name already exists. If you don\'t want to use ' From 6170ceb06f78938d32427fa4ae57fb7e9e16e23b Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 00:54:10 +0100 Subject: [PATCH 05/12] Removed alternative ToolchainCL implementation --- pythonforandroid/toolchain.py | 318 ---------------------------------- 1 file changed, 318 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 8d1b3cf06c..ed45008d55 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -147,324 +147,6 @@ def split_argument_list(l): return re.split(r'[ ,]+', l) -# class NewToolchainCL(object): -# def __init__(self): -# parser = argparse.ArgumentParser( -# description=('A packaging tool for turning Python scripts and apps ' -# 'into Android APKs')) - -# parser.add_argument( -# '--debug', dest='debug', action='store_true', -# help='Display debug output and all build info') -# parser.add_argument( -# '--color', dest='color', choices=['always', 'never', 'auto'], -# help='Enable or disable color output (default enabled on tty)') -# parser.add_argument( -# '--sdk-dir', '--sdk_dir', dest='sdk_dir', default='', -# help='The filepath where the Android SDK is installed') -# parser.add_argument( -# '--ndk-dir', '--ndk_dir', dest='ndk_dir', default='', -# help='The filepath where the Android NDK is installed') -# parser.add_argument( -# '--android-api', '--android_api', dest='android_api', default=0, type=int, -# help='The Android API level to build against.') -# parser.add_argument( -# '--ndk-version', '--ndk_version', dest='ndk_version', default='', -# help=('The version of the Android NDK. This is optional, ' -# 'we try to work it out automatically from the ndk_dir.')) - -# default_storage_dir = user_data_dir('python-for-android') -# if ' ' in default_storage_dir: -# default_storage_dir = '~/.python-for-android' -# parser.add_argument( -# '--storage-dir', dest='storage_dir', -# default=default_storage_dir, -# help=('Primary storage directory for downloads and builds ' -# '(default: {})'.format(default_storage_dir))) - -# # AND: This option doesn't really fit in the other categories, the -# # arg structure needs a rethink -# parser.add_argument( -# '--arch', -# help='The archs to build for, separated by commas.', -# default='armeabi') - -# # Options for specifying the Distribution -# parser.add_argument( -# '--dist-name', '--dist_name', -# help='The name of the distribution to use or create', -# default='') - -# parser.add_argument( -# '--requirements', -# help=('Dependencies of your app, should be recipe names or ' -# 'Python modules'), -# default='') - -# parser.add_argument( -# '--bootstrap', -# help='The bootstrap to build with. Leave unset to choose automatically.', -# default=None) - -# add_boolean_option( -# parser, ["allow-download"], -# default=False, -# description='Whether to allow binary dist download:') - -# add_boolean_option( -# parser, ["allow-build"], -# default=True, -# description='Whether to allow compilation of a new distribution:') - -# add_boolean_option( -# parser, ["force-build"], -# default=False, -# description='Whether to force compilation of a new distribution:') - -# parser.add_argument( -# '--extra-dist-dirs', '--extra_dist_dirs', -# dest='extra_dist_dirs', default='', -# help='Directories in which to look for distributions') - -# add_boolean_option( -# parser, ["require-perfect-match"], -# default=False, -# 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') - -# add_boolean_option( -# parser, ['copy-libs'], -# default=False, -# description='Copy libraries instead of using biglink (Android 4.3+)') - - -# subparsers = parser.add_subparsers(dest='subparser_name', -# help='The command to run') - -# parser_recipes = subparsers.add_parser( -# 'recipes', help='List the available recipes') -# parser_recipes.add_argument( -# "--compact", action="store_true", default=False, -# help="Produce a compact list suitable for scripting") - -# parser_bootstraps = subparsers.add_parser( -# 'bootstraps', help='List the available bootstraps') -# parser_clean_all = subparsers.add_parser( -# 'clean_all', aliases=['clean-all'], -# help='Delete all builds, dists and caches') -# parser_clean_dists = subparsers.add_parser( -# 'clean_dists', aliases=['clean-dists'], -# help='Delete all dists') -# parser_clean_bootstrap_builds = subparsers.add_parser( -# 'clean_bootstrap_builds', aliases=['clean-bootstrap-builds'], -# help='Delete all bootstrap builds') -# parser_clean_builds = subparsers.add_parser( -# 'clean_builds', aliases=['clean-builds'], -# help='Delete all builds') - -# parser_clean_recipe_build = subparsers.add_parser( -# 'clean_recipe_build', aliases=['clean-recipe-build'], -# help='Delete the build info for the given recipe') -# parser_clean_recipe_build.add_argument('recipe', help='The recipe name') - -# parser_clear_download_cache= subparsers.add_parser( -# 'clear_download_cache', aliases=['clear-download-cache'], -# help='Delete any cached recipe downloads') -# parser_export_dist = subparsers.add_parser( -# 'export_dist', aliases=['export-dist'], -# help='Copy the named dist to the given path') -# parser_symlink_dist = subparsers.add_parser( -# 'symlink_dist', aliases=['symlink-dist'], -# help='Symlink the named dist at the given path') -# # todo: make symlink an option of export -# parser_apk = subparsers.add_parser( -# 'apk', help='Build an APK') -# parser_create = subparsers.add_parser( -# 'create', help='Compile a set of requirements into a dist') -# parser_context_info = subparsers.add_parser( -# 'context_info', aliases=['context-info'], -# help='Print some debug information about the build context') -# parser_archs = subparsers.add_parser( -# 'archs', help='List the available target architectures') -# parser_distributions = subparsers.add_parser( -# 'distributions', aliases=['dists'], -# help='List the currently available (compiled) dists') -# parser_delete_dist = subparsers.add_parser( -# 'delete_dist', aliases=['delete-dist'], help='Delete a compiled dist') - -# parser_sdk_tools = subparsers.add_parser( -# 'sdk_tools', aliases=['sdk-tools'], -# help='Run the given binary from the SDK tools dis') -# parser_sdk_tools.add_argument('tool', help=('The tool binary name to run')) - -# parser_adb = subparsers.add_parser( -# 'adb', help='Run adb from the given SDK') -# parser_logcat = subparsers.add_parser( -# 'logcat', help='Run logcat from the given SDK') -# parser_build_status = subparsers.add_parser( -# 'build_status', aliases=['build-status'], -# help='Print some debug information about current built components') - -# parser_distributions.set_defaults(func=self.distributions) - -# print('ready to parse') -# args = parser.parse_args(sys.argv[1:]) -# print('parsed') - -# setup_color(args.color) - -# # strip version from requirements, and put them in environ -# requirements = [] -# for requirement in split_argument_list(args.requirements): -# if "==" in requirement: -# requirement, version = requirement.split(u"==", 1) -# os.environ["VERSION_{}".format(requirement)] = version -# info('Recipe {}: version "{}" requested'.format( -# requirement, version)) -# requirements.append(requirement) -# args.requirements = u",".join(requirements) - -# self.ctx = Context() -# self.storage_dir = args.storage_dir -# self.ctx.setup_dirs(self.storage_dir) -# self.sdk_dir = args.sdk_dir -# self.ndk_dir = args.ndk_dir -# self.android_api = args.android_api -# self.ndk_version = args.ndk_version - -# self._archs = split_argument_list(args.arch) - -# # AND: Fail nicely if the args aren't handled yet -# if args.extra_dist_dirs: -# warning('Received --extra_dist_dirs but this arg currently is not ' -# 'handled, exiting.') -# exit(1) - -# self.ctx.local_recipes = args.local_recipes -# self.ctx.copy_libs = args.copy_libs - -# # Each subparser corresponds to a method -# getattr(self, args.subparser_name.replace('-', '_'))(args) - -# def dists(self, args): -# print('args', args) -# self.distributions(args) - -# def distributions(self, args): -# '''Lists all distributions currently available (i.e. that have already -# been built).''' -# ctx = self.ctx -# dists = Distribution.get_distributions(ctx) - -# if dists: -# print('{Style.BRIGHT}Distributions currently installed are:' -# '{Style.RESET_ALL}'.format(Style=Out_Style, Fore=Out_Fore)) -# pretty_log_dists(dists, print) -# else: -# print('{Style.BRIGHT}There are no dists currently built.' -# '{Style.RESET_ALL}'.format(Style=Out_Style)) - -# def context_info(self, args): -# '''Prints some debug information about which system paths -# python-for-android will internally use for package building, along -# with information about where the Android SDK and NDK will be called -# from.''' -# ctx = self.ctx -# for attribute in ('root_dir', 'build_dir', 'dist_dir', 'libs_dir', -# 'eccache', 'cython', 'sdk_dir', 'ndk_dir', -# 'ndk_platform', 'ndk_ver', 'android_api'): -# print('{} is {}'.format(attribute, getattr(ctx, attribute))) - -# def archs(self, args): -# '''List the target architectures available to be built for.''' -# print('{Style.BRIGHT}Available target architectures are:' -# '{Style.RESET_ALL}'.format(Style=Out_Style)) -# for arch in self.ctx.archs: -# print(' {}'.format(arch.arch)) - -# def delete_dist(self, args): -# dist = self._dist -# if dist.needs_build: -# info('No dist exists that matches your specifications, ' -# 'exiting without deleting.') -# shutil.rmtree(dist.dist_dir) - -# def sdk_tools(self, args): -# '''Runs the android binary from the detected SDK directory, passing -# all arguments straight to it. This binary is used to install -# e.g. platform-tools for different API level targets. This is -# intended as a convenience function if android is not in your -# $PATH. -# ''' -# ctx = self.ctx -# ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, -# user_ndk_dir=self.ndk_dir, -# user_android_api=self.android_api, -# user_ndk_ver=self.ndk_version) -# android = sh.Command(join(ctx.sdk_dir, 'tools', args.tool)) -# output = android( -# *unknown, _iter=True, _out_bufsize=1, _err_to_out=True) -# for line in output: -# sys.stdout.write(line) -# sys.stdout.flush() - -# def adb(self, args): -# '''Runs the adb binary from the detected SDK directory, passing all -# arguments straight to it. This is intended as a convenience -# function if adb is not in your $PATH. -# ''' -# ctx = self.ctx -# ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, -# user_ndk_dir=self.ndk_dir, -# user_android_api=self.android_api, -# user_ndk_ver=self.ndk_version) -# if platform in ('win32', 'cygwin'): -# adb = sh.Command(join(ctx.sdk_dir, 'platform-tools', 'adb.exe')) -# else: -# adb = sh.Command(join(ctx.sdk_dir, 'platform-tools', 'adb')) -# info_notify('Starting adb...') -# output = adb(args, _iter=True, _out_bufsize=1, _err_to_out=True) -# for line in output: -# sys.stdout.write(line) -# sys.stdout.flush() - -# def logcat(self, args): -# '''Runs ``adb logcat`` using the adb binary from the detected SDK -# directory. All extra args are passed as arguments to logcat.''' -# self.adb(['logcat'] + args) - - -# def build_status(self, args): - -# print('{Style.BRIGHT}Bootstraps whose core components are probably ' -# 'already built:{Style.RESET_ALL}'.format(Style=Out_Style)) -# for filen in os.listdir(join(self.ctx.build_dir, 'bootstrap_builds')): -# print(' {Fore.GREEN}{Style.BRIGHT}{filen}{Style.RESET_ALL}' -# .format(filen=filen, Fore=Out_Fore, Style=Out_Style)) - -# print('{Style.BRIGHT}Recipes that are probably already built:' -# '{Style.RESET_ALL}'.format(Style=Out_Style)) -# if exists(join(self.ctx.build_dir, 'other_builds')): -# for filen in sorted( -# os.listdir(join(self.ctx.build_dir, 'other_builds'))): -# name = filen.split('-')[0] -# dependencies = filen.split('-')[1:] -# recipe_str = (' {Style.BRIGHT}{Fore.GREEN}{name}' -# '{Style.RESET_ALL}'.format( -# Style=Out_Style, name=name, Fore=Out_Fore)) -# if dependencies: -# recipe_str += ( -# ' ({Fore.BLUE}with ' + ', '.join(dependencies) + -# '{Fore.RESET})').format(Fore=Out_Fore) -# recipe_str += '{Style.RESET_ALL}'.format(Style=Out_Style) -# print(recipe_str) - - class ToolchainCL(object): def __init__(self): From acb869bf91f6dc7d87113e3002abe3de0b103aeb Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 00:55:15 +0100 Subject: [PATCH 06/12] Removed (now-defunct) references to new_main --- pythonforandroid/toolchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index ed45008d55..e89bc7da68 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -754,4 +754,4 @@ def main(): # NewToolchainCL() if __name__ == "__main__": - new_main() + main() From f403a22095c39c1e3d7b72ce9bf88ee97e1a430a Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 00:55:44 +0100 Subject: [PATCH 07/12] Removed debug comment --- pythonforandroid/toolchain.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index e89bc7da68..3edc5a445a 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -751,7 +751,6 @@ def build_status(self, args): def main(): ToolchainCL() - # NewToolchainCL() if __name__ == "__main__": main() From ad352fefc58974556b6edb74404e36533db0bc1e Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 01:14:30 +0100 Subject: [PATCH 08/12] Fixed apk command argument passing --- pythonforandroid/toolchain.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 3edc5a445a..5480e1649f 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -566,32 +566,33 @@ def apk(self, args): # they are in the current directory. fix_args = ('--dir', '--private', '--add-jar', '--add-source', '--whitelist', '--blacklist', '--presplash', '--icon') - for i, arg in enumerate(args[:-1]): + unknown_args = args.unknown_args + for i, arg in enumerate(unknown_args[:-1]): argx = arg.split('=') if argx[0] in fix_args: if len(argx) > 1: - args[i] = '='.join((argx[0], + unknown_args[i] = '='.join((argx[0], realpath(expanduser(argx[1])))) else: - args[i+1] = realpath(expanduser(args[i+1])) + unknown_args[i+1] = realpath(expanduser(unknown_args[i+1])) env = os.environ.copy() - if apk_args.build_mode == 'release': - if apk_args.keystore: - env['P4A_RELEASE_KEYSTORE'] = realpath(expanduser(apk_args.keystore)) - if apk_args.signkey: - env['P4A_RELEASE_KEYALIAS'] = apk_args.signkey - if apk_args.keystorepw: - env['P4A_RELEASE_KEYSTORE_PASSWD'] = apk_args.keystorepw - if apk_args.signkeypw: - env['P4A_RELEASE_KEYALIAS_PASSWD'] = apk_args.signkeypw - elif apk_args.keystorepw and 'P4A_RELEASE_KEYALIAS_PASSWD' not in env: - env['P4A_RELEASE_KEYALIAS_PASSWD'] = apk_args.keystorepw + if args.build_mode == 'release': + if args.keystore: + env['P4A_RELEASE_KEYSTORE'] = realpath(expanduser(args.keystore)) + if args.signkey: + env['P4A_RELEASE_KEYALIAS'] = args.signkey + if args.keystorepw: + env['P4A_RELEASE_KEYSTORE_PASSWD'] = args.keystorepw + if args.signkeypw: + env['P4A_RELEASE_KEYALIAS_PASSWD'] = args.signkeypw + elif args.keystorepw and 'P4A_RELEASE_KEYALIAS_PASSWD' not in env: + env['P4A_RELEASE_KEYALIAS_PASSWD'] = args.keystorepw build = imp.load_source('build', join(dist.dist_dir, 'build.py')) with current_directory(dist.dist_dir): build_args = build.parse_args(args.unknown_args) - output = shprint(sh.ant, apk_args.build_mode, _tail=20, _critical=True, _env=env) + output = shprint(sh.ant, args.build_mode, _tail=20, _critical=True, _env=env) info_main('# Copying APK to current directory') @@ -605,7 +606,7 @@ def apk(self, args): if not apk_file: info_main('# APK filename not found in build output, trying to guess') - apks = glob.glob(join(dist.dist_dir, 'bin', '*-*-{}.apk'.format(apk_args.build_mode))) + apks = glob.glob(join(dist.dist_dir, 'bin', '*-*-{}.apk'.format(args.build_mode))) if len(apks) == 0: raise ValueError('Couldn\'t find the built APK') if len(apks) > 1: From 56122d73b90b2f9705df965ab5b62fda620e400e Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 01:49:41 +0100 Subject: [PATCH 09/12] Made symlink an option of export-dist --- pythonforandroid/toolchain.py | 40 ++++++----------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 5480e1649f..302110eb2f 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -287,16 +287,9 @@ def __init__(self): 'export_dist', aliases=['export-dist'], help='Copy the named dist to the given path', parents=[generic_parser]) - parser_export_dist.add_argument('--output', help=('The output dir to copy to'), - required=True) - - parser_symlink_dist = subparsers.add_parser( - 'symlink_dist', aliases=['symlink-dist'], - help='Symlink the named dist at the given path', - parents=[generic_parser]) - parser_symlink_dist.add_argument('--output', help=('The output dir to copy to'), - required=True) - # todo: make symlink an option of export + parser_export_dist.add_argument('output_dir', help=('The output dir to copy to')) + parser_export_dist.add_argument('--symlink', action='store_true', + help=('Symlink the dist instead of copying')) parser_apk = subparsers.add_parser( 'apk', help='Build an APK', @@ -523,29 +516,10 @@ def export_dist(self, args): 'with suitable recipes available. For now, you must ' ' create one first with the create argument.') exit(1) - shprint(sh.cp, '-r', dist.dist_dir, args.output) - - @require_prebuilt_dist - def symlink_dist(self, args): - '''Symlinks a created dist to an output dir. - - This makes it easy to navigate to the dist to investigate it - or call build.py, though you do not in general need to do this - and can use the apk command instead. - - ''' - ctx = self.ctx - dist = dist_from_args(ctx, args) - if dist.needs_build: - info('You asked to symlink a dist, but there is no dist ' - 'with suitable recipes available. For now, you must ' - 'create one first with the create argument.') - exit(1) - shprint(sh.ln, '-s', dist.dist_dir, args.output) - - # def _get_dist(self): - # ctx = self.ctx - # dist = dist_from_args(ctx, self.args) + if args.symlink: + shprint(sh.ln, '-s', dist.dist_dir, args.output_dir) + else: + shprint(sh.cp, '-r', dist.dist_dir, args.output_dir) @property def _dist(self): From 0c0e0514d831857c38e0994c1f10e3ae1928d0df Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 13:00:32 +0100 Subject: [PATCH 10/12] Updated toolchain.py docstring --- pythonforandroid/toolchain.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 302110eb2f..6fef2192bb 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -1,9 +1,9 @@ #!/usr/bin/env python """ -Tool for compiling Android toolchain -==================================== +Tool for packaging Python apps for Android +========================================== -This tool intend to replace all the previous tools/ in shell script. +This module defines the entry point for command line and programmatic use. """ from __future__ import print_function @@ -16,7 +16,6 @@ import shutil import re import imp -import logging import shlex from functools import wraps From 8d7f8998d31f2f54b751d87e9316788ed43c08e9 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 14:40:01 +0100 Subject: [PATCH 11/12] Fixed adb calling with new args structure --- pythonforandroid/toolchain.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 6fef2192bb..2757869e13 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -667,7 +667,7 @@ def sdk_tools(self, args): user_ndk_ver=self.ndk_version) android = sh.Command(join(ctx.sdk_dir, 'tools', args.tool)) output = android( - *unknown, _iter=True, _out_bufsize=1, _err_to_out=True) + *args.unknown_args, _iter=True, _out_bufsize=1, _err_to_out=True) for line in output: sys.stdout.write(line) sys.stdout.flush() @@ -677,6 +677,16 @@ def adb(self, args): arguments straight to it. This is intended as a convenience function if adb is not in your $PATH. ''' + self._adb(args.unknown_args) + + def logcat(self, args): + '''Runs ``adb logcat`` using the adb binary from the detected SDK + directory. All extra args are passed as arguments to logcat.''' + self._adb(['logcat'] + args.unknown_args) + + def _adb(self, commands): + '''Call the adb executable from the SDK, passing the given commands as + arguments.''' ctx = self.ctx ctx.prepare_build_environment(user_sdk_dir=self.sdk_dir, user_ndk_dir=self.ndk_dir, @@ -687,15 +697,11 @@ def adb(self, args): else: adb = sh.Command(join(ctx.sdk_dir, 'platform-tools', 'adb')) info_notify('Starting adb...') - output = adb(args, _iter=True, _out_bufsize=1, _err_to_out=True) + output = adb(*commands, _iter=True, _out_bufsize=1, _err_to_out=True) for line in output: sys.stdout.write(line) sys.stdout.flush() - - def logcat(self, args): - '''Runs ``adb logcat`` using the adb binary from the detected SDK - directory. All extra args are passed as arguments to logcat.''' - self.adb(['logcat'] + args.unknown_args) + def build_status(self, args): From e0cb1beadcb4e591b702f548b3ddd096da47e753 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 2 Jul 2016 14:47:31 +0100 Subject: [PATCH 12/12] Removed broken command --- pythonforandroid/toolchain.py | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/pythonforandroid/toolchain.py b/pythonforandroid/toolchain.py index 2757869e13..c097ca598a 100644 --- a/pythonforandroid/toolchain.py +++ b/pythonforandroid/toolchain.py @@ -309,10 +309,6 @@ def __init__(self): parser_create = subparsers.add_parser( 'create', help='Compile a set of requirements into a dist', parents=[generic_parser]) - parser_context_info = subparsers.add_parser( - 'context_info', aliases=['context-info'], - help='Print some debug information about the build context', - parents=[generic_parser]) parser_archs = subparsers.add_parser( 'archs', help='List the available target architectures', parents=[generic_parser]) @@ -595,31 +591,7 @@ def create(self, args): '''Create a distribution directory if it doesn't already exist, run any recipes if necessary, and build the apk. ''' - pass # The decorator does this for us - # ctx = self.ctx - - # dist = dist_from_args(ctx, self.args) - # if not dist.needs_build: - # info('You asked to create a distribution, but a dist with ' - # 'this name already exists. If you don\'t want to use ' - # 'it, you must delete it and rebuild, or create your ' - # 'new dist with a different name.') - # exit(1) - # info('Ready to create dist {}, contains recipes {}'.format( - # dist.name, ', '.join(dist.recipes))) - - # build_dist_from_args(ctx, dist, args) - - def context_info(self, args): - '''Prints some debug information about which system paths - python-for-android will internally use for package building, along - with information about where the Android SDK and NDK will be called - from.''' - ctx = self.ctx - for attribute in ('root_dir', 'build_dir', 'dist_dir', 'libs_dir', - 'ccache', 'cython', 'sdk_dir', 'ndk_dir', - 'ndk_platform', 'ndk_ver', 'android_api'): - print('{} is {}'.format(attribute, getattr(ctx, attribute))) + pass # The decorator does everything def archs(self, args): '''List the target architectures available to be built for.'''