Upgrade p4a #19

Open
jessopb wants to merge 36 commits from upgrade_p4a into master
3 changed files with 174 additions and 42 deletions
Showing only changes of commit 5a103bfbee - Show all commits

View file

@ -237,7 +237,7 @@ main.py that loads it.''')
# Delete the old assets.
shutil.rmtree(assets_dir, ignore_errors=True)
ensure_dir(assets_dir)
# remove make_python_zip()
# Add extra environment variable file into tar-able directory:
env_vars_tarpath = tempfile.mkdtemp(prefix="p4a-extra-env-")
with open(os.path.join(env_vars_tarpath, "p4a_env_vars.txt"), "w") as f:
@ -251,7 +251,7 @@ main.py that loads it.''')
# Package up the private data (public not supported).
use_setup_py = get_dist_info_for("use_setup_py",
error_if_missing=False) is True
private_tar_dirs = [env_vars_tarpath]
tar_dirs = [env_vars_tarpath]
_temp_dirs_to_clean = []
try:
if args.private:
@ -261,13 +261,22 @@ main.py that loads it.''')
):
print('No setup.py/pyproject.toml used, copying '
'full private data into .apk.')
private_tar_dirs.append(args.private)
tar_dirs.append(args.private)
else:
print("Copying main.py's ONLY, since other app data is "
"expected in site-packages.")
main_py_only_dir = tempfile.mkdtemp()
_temp_dirs_to_clean.append(main_py_only_dir)
# skip this:
# if exists(join(args.private, "main.pyo")):
# shutil.copyfile(join(args.private, "main.pyo"),
# join(main_py_only_dir, "main.pyo"))
# elif exists(join(args.private, "main.py")):
# shutil.copyfile(join(args.private, "main.py"),
# join(main_py_only_dir, "main.py"))
# tar_dirs.append(main_py_only_dir)
# Check all main.py files we need to copy:
copy_paths = ["main.py", join("service", "main.py")]
for copy_path in copy_paths:
@ -292,10 +301,10 @@ main.py that loads it.''')
)
# Append directory with all main.py's to result apk paths:
private_tar_dirs.append(main_py_only_dir)
if get_bootstrap_name() == "webview":
for asset in listdir('webview_includes'):
shutil.copy(join('webview_includes', asset), join(assets_dir, asset))
tar_dirs.append(main_py_only_dir)
# if get_bootstrap_name() == "webview":
# for asset in listdir('webview_includes'):
# shutil.copy(join('webview_includes', asset), join(assets_dir, asset))
for asset in args.assets:
asset_src, asset_dest = asset.split(":")
@ -316,7 +325,7 @@ main.py that loads it.''')
)
make_tar(
join(assets_dir, "private.tar"),
private_tar_dirs,
tar_dirs,
byte_compile_python=args.byte_compile_python,
optimize_python=args.optimize_python,
)

View file

@ -10,6 +10,7 @@ import tarfile
import time
import subprocess
import shutil
import json
from zipfile import ZipFile
import sys
from distutils.version import LooseVersion
@ -18,12 +19,58 @@ from fnmatch import fnmatch
import jinja2
## WHAT IS DISTINFO>JSON?
def get_dist_info_for(key):
try:
with open(join(dirname(__file__), 'dist_info.json'), 'r') as fileh:
info = json.load(fileh)
bootstrap = str(info["bootstrap"])
value = str(info[key])
except (OSError, KeyError) as e:
print("BUILD FAILURE: Couldn't extract bootstrap name " +
print("BUILD FAILURE: Couldn't extract the key `" + key + "` " +
"from dist_info.json: " + str(e))
sys.exit(1)
return bootstrap
return value
def get_hostpython():
return get_dist_info_for('hostpython')
def get_python_version():
return get_dist_info_for('python_version')
def get_bootstrap_name():
return get_dist_info_for('python_version')
def get_bootstrap_name():
# try:
# with open(join(dirname(__file__), 'dist_info.json'), 'r') as fileh:
# info = json.load(fileh)
# bootstrap = str(info["bootstrap"])
# except (OSError, KeyError) as e:
# print("BUILD FAILURE: Couldn't extract bootstrap name " +
# "from dist_info.json: " + str(e))
# sys.exit(1)
# return bootstrap
return get_dist_info_for('bootstrap')
if os.name == 'nt':
ANDROID = 'android.bat'
ANT = 'ant.bat'
else:
ANDROID = 'android'
ANT = 'ant'
curdir = dirname(__file__)
# Try to find a host version of Python that matches our ARM version.
PYTHON = join(curdir, 'python-install', 'bin', 'python.host')
# PYTHON = join(curdir, 'python-install', 'bin', 'python.host')
PYTHON = get_python_version()
if not exists(PYTHON):
print('Could not find hostpython, will not compile to .pyo (this is normal with python3)')
PYTHON = None
BLACKLIST_PATTERNS = [
@ -125,7 +172,6 @@ def make_python_zip():
if not exists('private'):
print('No compiled python is present to zip, skipping.')
print('this should only be the case if you are using the CrystaX python')
return
global python_files
@ -158,7 +204,7 @@ def make_python_zip():
zf.close()
def make_tar(tfn, source_dirs, ignore_path=[]):
def make_tar(tfn, source_dirs, ignore_path=[], optimize_python=True):
'''
Make a zip file `fn` from the contents of source_dis.
'''
@ -179,7 +225,7 @@ def make_tar(tfn, source_dirs, ignore_path=[]):
files = []
for sd in source_dirs:
sd = realpath(sd)
compile_dir(sd)
compile_dir(sd, optimize_python=optimize_python)
files += [(x, relpath(realpath(x), sd)) for x in listfiles(sd)
if select(x)]
@ -208,18 +254,27 @@ def make_tar(tfn, source_dirs, ignore_path=[]):
tf.close()
def compile_dir(dfn):
def compile_dir(dfn, optimize_python=True):
'''
Compile *.py in directory `dfn` to *.pyo
'''
# -OO = strip docstrings
if PYTHON is None:
return
subprocess.call([PYTHON, '-OO', '-m', 'compileall', '-f', dfn])
args = [PYTHON, '-m', 'compileall', '-b', '-f', dfn]
if optimize_python:
# -OO = strip docstrings
args.insert(1, '-OO')
return_code = subprocess.call(args)
if return_code != 0:
print('Error while running "{}"'.format(' '.join(args)))
print('This probably means one of your Python files has a syntax '
'error, see logs above')
exit(1)
def make_package(args):
# Ignore warning if the launcher is in args
# since boostrap is 'lbry', removed get_bootstrap_name checks
if not args.launcher:
if not (exists(join(realpath(args.private), 'main.py')) or
exists(join(realpath(args.private), 'main.pyo'))):
@ -229,20 +284,23 @@ started by a file with a different name, rename it to main.py or add a
main.py that loads it.''')
exit(1)
assets_dir = "src/main/assets"
# Delete the old assets.
try_unlink('src/main/assets/public.mp3')
try_unlink('src/main/assets/private.mp3')
try_unlink(join(assets_dir, 'public.mp3'))
try_unlink(join(assets_dir, 'private.mp3'))
ensure_dir(assets_dir)
# In order to speedup import and initial depack,
# construct a python27.zip
# still here as of 12/18/18
make_python_zip()
# Package up the private data (public not supported).
tar_dirs = [args.private]
if exists('private'):
tar_dirs.append('private')
if exists('crystax_python'):
tar_dirs.append('crystax_python')
for python_bundle_dir in ('private', 'crystax_python', '_python_bundle'):
if exists(python_bundle_dir):
tar_dirs.append(python_bundle_dir)
if args.private:
make_tar('src/main/assets/private.mp3', tar_dirs, args.ignore_path)
@ -255,9 +313,13 @@ main.py that loads it.''')
url_scheme = 'kivy'
# Prepare some variables for templating process
res_dir = "src/main/res"
# bootstrap is lbry so we def need these
default_icon = 'templates/lbry-icon.png'
default_presplash = 'templates/kivy-presplash.jpg'
shutil.copy(args.icon or default_icon, 'src/main/res/drawable/icon.png')
shutil.copy(args.icon or default_icon,
join(res_dir, 'drawable/icon.png')
)
shutil.copy(args.presplash or default_presplash,
'src/main/res/drawable/presplash.jpg')
@ -324,9 +386,15 @@ main.py that loads it.''')
sticky = 'sticky' in options
service_names.append(name)
# 12/18/18
service_target_path = \
'src/main/java/{}/Service{}.java'.format(
args.package.replace(".", "/"),
name.capitalize()
)
render(
'Service.tmpl.java',
'src/main/java/{}/Service{}.java'.format(args.package.replace(".", "/"), name.capitalize()),
service_target_path,
name=name,
entrypoint=entrypoint,
args=args,
@ -359,11 +427,13 @@ main.py that loads it.''')
# Copy the AndroidManifest.xml to the dist root dir so that ant
# can also use it
manifest_path = "src/main/AndroidManifest.xml"
if exists('AndroidManifest.xml'):
remove('AndroidManifest.xml')
shutil.copy(join('src', 'main', 'AndroidManifest.xml'),
'AndroidManifest.xml')
# String resources
render(
'strings.tmpl.xml',
'src/main/res/values/strings.xml',
@ -423,10 +493,11 @@ main.py that loads it.''')
args=args,
versioned_name=versioned_name)
render(
'custom_rules.tmpl.xml',
'custom_rules.xml',
args=args)
if exists(join("templates", "custom_rules.tmpl.xml")):
render(
'custom_rules.tmpl.xml',
'custom_rules.xml',
args=args)
if args.sign:
@ -435,9 +506,44 @@ main.py that loads it.''')
if exists('build.properties'):
os.remove('build.properties')
# # Apply java source patches if any are present:
# if exists(join('src', 'patches')):
# print("Applying Java source code patches...")
# for patch_name in os.listdir(join('src', 'patches')):
# patch_path = join('src', 'patches', patch_name)
# print("Applying patch: " + str(patch_path))
# try:
# subprocess.check_output([
# # -N: insist this is FORWARd patch, don't reverse apply
# # -p1: strip first path component
# # -t: batch mode, don't ask questions
# "patch", "-N", "-p1", "-t", "-i", patch_path
# ])
# except subprocess.CalledProcessError as e:
# if e.returncode == 1:
# # Return code 1 means it didn't apply, this will
# # usually mean it is already applied.
# print("Warning: failed to apply patch (" +
# "exit code 1), " +
# "assuming it is already applied: " +
# str(patch_path)
# )
# else:
# raise e
def parse_args(args=None):
global BLACKLIST_PATTERNS, WHITELIST_PATTERNS, PYTHON
default_android_api = 12
default_android_api = 21
# Get the default minsdk, equal to the NDK API that this dist it built against
with open('dist_info.json', 'r') as fileh:
info = json.load(fileh)
if 'ndk_api' not in info:
print('Failed to read ndk_api from dist info')
default_android_api = 12 # The old default before ndk_api was introduced
else:
default_android_api = info['ndk_api']
ndk_api = info['ndk_api']
import argparse
ap = argparse.ArgumentParser(description='''\
Package a Python application for Android.
@ -551,8 +657,18 @@ tools directory of the Android SDK.
if args.name and args.name[0] == '"' and args.name[-1] == '"':
args.name = args.name[1:-1]
# if args.sdk_version == -1:
# args.sdk_version = args.min_sdk_version
if ndk_api != args.min_sdk_version:
print(('WARNING: --minsdk argument does not match the api that is '
'compiled against. Only proceed if you know what you are '
'doing, otherwise use --minsdk={} or recompile against api '
'{}').format(ndk_api, args.min_sdk_version))
if not args.allow_minsdk_ndkapi_mismatch:
print('You must pass --allow-minsdk-ndkapi-mismatch to build '
'with --minsdk different to the target NDK api from the '
'build step')
exit(1)
else:
print('Proceeding with --minsdk not matching build target api')
if args.sdk_version != -1:
print('WARNING: Received a --sdk argument, but this argument is '
@ -573,14 +689,14 @@ tools directory of the Android SDK.
if args.try_system_python_compile:
# Hardcoding python2.7 is okay for now, as python3 skips the
# compilation anyway
if not exists('crystax_python'):
python_executable = 'python2.7'
try:
subprocess.call([python_executable, '--version'])
except (OSError, subprocess.CalledProcessError):
pass
else:
PYTHON = python_executable
python_executable = 'python2.7'
try:
subprocess.call([python_executable, '--version'])
except (OSError, subprocess.CalledProcessError):
pass
else:
PYTHON = python_executable
if args.no_compile_pyo:
PYTHON = None
@ -598,6 +714,9 @@ tools directory of the Android SDK.
if x.strip() and not x.strip().startswith('#')]
WHITELIST_PATTERNS += patterns
if args.private is None:
print('Need --private directory with app files to package for .apk')
exit(1)
make_package(args)
return args

View file

@ -23,7 +23,7 @@ else:
# don't use sh after 1.12.5, we have performance issues
# https://github.com/amoffat/sh/issues/378
install_reqs = ['appdirs', 'colorama>=0.3.3', 'sh>=1.10,<1.12.5', 'jinja2',
'six']
'six', 'enum34']
# By specifying every file manually, package_data will be able to
# include them in binary distributions. Note that we have to add
@ -54,13 +54,17 @@ recursively_include(package_data, 'pythonforandroid/bootstraps/webview',
recursively_include(package_data, 'pythonforandroid',
['liblink', 'biglink', 'liblink.sh'])
with open(join(dirname(__file__), 'README.rst')) as fileh:
with open(join(dirname(__file__), 'README.md',
encoding="utf-8",
errors="replace")) as fileh:
long_description = fileh.read()
init_filen = join(dirname(__file__), 'pythonforandroid', '__init__.py')
version = None
try:
with open(init_filen) as fileh:
with open(init_filen,
encoding="utf-8",
errors="replace") as fileh:
lines = fileh.readlines()
except IOError:
pass