Merge branch 'master' into garden_requirements
This commit is contained in:
commit
df02289ac0
5 changed files with 201 additions and 29 deletions
|
@ -64,7 +64,7 @@ Usage
|
|||
clean Clean the whole Buildozer environment.
|
||||
help Show the Buildozer help.
|
||||
init Create a initial buildozer.spec in the current directory
|
||||
setdefault Set the default command to do when to arguments are given
|
||||
setdefault Set the default command to do when no arguments are given
|
||||
version Show the Buildozer version
|
||||
|
||||
Target commands:
|
||||
|
|
|
@ -10,13 +10,15 @@ Layout directory for buildozer:
|
|||
|
||||
'''
|
||||
|
||||
__version__ = '0.7'
|
||||
__version__ = '0.9'
|
||||
|
||||
import fcntl
|
||||
import os
|
||||
import re
|
||||
import shelve
|
||||
import SimpleHTTPServer
|
||||
import socket
|
||||
import SocketServer
|
||||
import sys
|
||||
import zipfile
|
||||
from select import select
|
||||
|
@ -47,6 +49,7 @@ USE_COLOR = 'NO_COLOR' not in environ
|
|||
# error, info, debug
|
||||
LOG_LEVELS_C = (RED, BLUE, BLACK)
|
||||
LOG_LEVELS_T = 'EID'
|
||||
SIMPLE_HTTP_SERVER_PORT = 8000
|
||||
|
||||
|
||||
class ChromeDownloader(FancyURLopener):
|
||||
|
@ -75,7 +78,8 @@ class BuildozerCommandException(BuildozerException):
|
|||
|
||||
class Buildozer(object):
|
||||
|
||||
standard_cmds = ('clean', 'update', 'debug', 'release', 'deploy', 'run')
|
||||
standard_cmds = ('clean', 'update', 'debug', 'release',
|
||||
'deploy', 'run', 'serve')
|
||||
|
||||
def __init__(self, filename='buildozer.spec', target=None):
|
||||
super(Buildozer, self).__init__()
|
||||
|
@ -86,7 +90,9 @@ class Buildozer(object):
|
|||
self.build_id = None
|
||||
self.config_profile = ''
|
||||
self.config = SafeConfigParser(allow_no_value=True)
|
||||
self.config.optionxform = lambda value: value
|
||||
self.config.getlist = self._get_config_list
|
||||
self.config.getlistvalues = self._get_config_list_values
|
||||
self.config.getdefault = self._get_config_default
|
||||
self.config.getbooldefault = self._get_config_bool
|
||||
|
||||
|
@ -361,7 +367,8 @@ class Buildozer(object):
|
|||
target_available_packages = self.target.get_available_packages()
|
||||
|
||||
# remove all the requirements that the target can compile
|
||||
requirements = [x for x in requirements if x not in
|
||||
onlyname = lambda x: x.split('==')[0]
|
||||
requirements = [x for x in requirements if onlyname(x) not in
|
||||
target_available_packages]
|
||||
|
||||
# did we already installed the libs ?
|
||||
|
@ -383,6 +390,10 @@ class Buildozer(object):
|
|||
|
||||
def _install_application_requirement(self, module):
|
||||
self._ensure_virtualenv()
|
||||
# resetup distribute, just in case
|
||||
self.debug('Install distribute')
|
||||
self.cmd('curl http://python-distribute.org/distribute_setup.py | venv/bin/python', get_stdout=True, cwd=self.buildozer_dir)
|
||||
|
||||
self.debug('Install requirement {} in virtualenv'.format(module))
|
||||
self.cmd('pip-2.7 install --download-cache={} --target={} {}'.format(
|
||||
self.global_cache_dir, self.applibs_dir, module),
|
||||
|
@ -502,6 +513,19 @@ class Buildozer(object):
|
|||
|
||||
raise Exception('Unhandled extraction for type {0}'.format(archive))
|
||||
|
||||
def file_copytree(self, src, dest):
|
||||
print 'copy {} to {}'.format(src, dest)
|
||||
if os.path.isdir(src):
|
||||
if not os.path.isdir(dest):
|
||||
os.makedirs(dest)
|
||||
files = os.listdir(src)
|
||||
for f in files:
|
||||
self.file_copytree(
|
||||
os.path.join(src, f),
|
||||
os.path.join(dest, f))
|
||||
else:
|
||||
copyfile(src, dest)
|
||||
|
||||
def clean_platform(self):
|
||||
self.info('Clean the platform build directory')
|
||||
if not exists(self.platform_dir):
|
||||
|
@ -662,6 +686,21 @@ class Buildozer(object):
|
|||
copyfile(join(dirname(__file__), 'sitecustomize.py'),
|
||||
join(self.app_dir, 'sitecustomize.py'))
|
||||
|
||||
main_py = join(self.app_dir, 'service', 'main.py')
|
||||
if not self.file_exists(main_py):
|
||||
#self.error('Unable to patch main_py to add applibs directory.')
|
||||
return
|
||||
|
||||
header = ('import sys, os; '
|
||||
'sys.path = [os.path.join(os.getcwd(),'
|
||||
'"..", "_applibs")] + sys.path\n')
|
||||
with open(main_py, 'rb') as fd:
|
||||
data = fd.read()
|
||||
data = header + data
|
||||
with open(main_py, 'wb') as fd:
|
||||
fd.write(data)
|
||||
self.info('Patched service/main.py to include applibs')
|
||||
|
||||
def namify(self, name):
|
||||
'''Return a "valid" name from a name with lot of invalid chars
|
||||
(allowed characters: a-z, A-Z, 0-9, -, _)
|
||||
|
@ -704,6 +743,10 @@ class Buildozer(object):
|
|||
def global_platform_dir(self):
|
||||
return join(self.global_buildozer_dir, self.targetname, 'platform')
|
||||
|
||||
@property
|
||||
def global_packages_dir(self):
|
||||
return join(self.global_buildozer_dir, self.targetname, 'packages')
|
||||
|
||||
@property
|
||||
def global_cache_dir(self):
|
||||
return join(self.global_buildozer_dir, 'cache')
|
||||
|
@ -760,12 +803,13 @@ class Buildozer(object):
|
|||
|
||||
print
|
||||
print 'Target commands:'
|
||||
print ' clean Clean the target environment'
|
||||
print ' update Update the target dependencies'
|
||||
print ' debug Build the application in debug mode'
|
||||
print ' release Build the application in release mode'
|
||||
print ' deploy Deploy the application on the device'
|
||||
print ' run Run the application on the device'
|
||||
print ' clean Clean the target environment'
|
||||
print ' update Update the target dependencies'
|
||||
print ' debug Build the application in debug mode'
|
||||
print ' release Build the application in release mode'
|
||||
print ' deploy Deploy the application on the device'
|
||||
print ' run Run the application on the device'
|
||||
print ' serve Serve the bin directory via SimpleHTTPServer'
|
||||
|
||||
for target, m in targets:
|
||||
mt = m.get_target(self)
|
||||
|
@ -828,7 +872,7 @@ class Buildozer(object):
|
|||
# maybe it's a target?
|
||||
targets = [x[0] for x in self.targets()]
|
||||
if command not in targets:
|
||||
print 'Unknow command/target', command
|
||||
print 'Unknown command/target', command
|
||||
exit(1)
|
||||
|
||||
self.set_target(command)
|
||||
|
@ -864,6 +908,16 @@ class Buildozer(object):
|
|||
'''
|
||||
print 'Buildozer {0}'.format(__version__)
|
||||
|
||||
def cmd_serve(self, *args):
|
||||
'''Serve the bin directory via SimpleHTTPServer
|
||||
'''
|
||||
os.chdir(self.bin_dir)
|
||||
handler = SimpleHTTPServer.SimpleHTTPRequestHandler
|
||||
httpd = SocketServer.TCPServer(("", SIMPLE_HTTP_SERVER_PORT), handler)
|
||||
print("Serving via HTTP at port {}".format(SIMPLE_HTTP_SERVER_PORT))
|
||||
print("Press Ctrl+c to quit serving.")
|
||||
httpd.serve_forever()
|
||||
|
||||
#
|
||||
# Private
|
||||
#
|
||||
|
@ -898,8 +952,11 @@ class Buildozer(object):
|
|||
|
||||
|
||||
|
||||
def _get_config_list_values(self, *args, **kwargs):
|
||||
kwargs['with_values'] = True
|
||||
return self._get_config_list(*args, **kwargs)
|
||||
|
||||
def _get_config_list(self, section, token, default=None):
|
||||
def _get_config_list(self, section, token, default=None, with_values=False):
|
||||
# monkey-patch method for ConfigParser
|
||||
# get a key as a list of string, seperated from the comma
|
||||
|
||||
|
@ -907,7 +964,11 @@ class Buildozer(object):
|
|||
l_section = '{}:{}'.format(section, token)
|
||||
if self.config.has_section(l_section):
|
||||
values = self.config.options(l_section)
|
||||
return [x.strip() for x in values]
|
||||
if with_values:
|
||||
return ['{}={}'.format(key, self.config.get(l_section, key)) for
|
||||
key in values]
|
||||
else:
|
||||
return [x.strip() for x in values]
|
||||
|
||||
values = self.config.getdefault(section, token, '')
|
||||
if not values:
|
||||
|
@ -966,7 +1027,7 @@ class BuildozerRemote(Buildozer):
|
|||
remote_name = args[0]
|
||||
remote_section = 'remote:{}'.format(remote_name)
|
||||
if not self.config.has_section(remote_section):
|
||||
self.error('Unknow remote "{}", must be configured first.'.format(
|
||||
self.error('Unknown remote "{}", must be configured first.'.format(
|
||||
remote_name))
|
||||
return
|
||||
|
||||
|
|
|
@ -67,7 +67,10 @@ fullscreen = 1
|
|||
#android.sdk = 21
|
||||
|
||||
# (str) Android NDK version to use
|
||||
#android.ndk = 8c
|
||||
#android.ndk = 9
|
||||
|
||||
# (bool) Use --private data storage (True) or --dir public storage (False)
|
||||
#android.private_storage = True
|
||||
|
||||
# (str) Android NDK directory (if empty, it will be automatically downloaded.)
|
||||
#android.ndk_path =
|
||||
|
@ -84,6 +87,10 @@ fullscreen = 1
|
|||
# OUYA-ODK/libs/*.jar
|
||||
#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
|
||||
|
||||
# (list) List of Java files to add to the android project (can be java or a
|
||||
# directory containing the files)
|
||||
#android.add_src =
|
||||
|
||||
# (str) python-for-android branch to use, if not master, useful to try
|
||||
# not yet merged features.
|
||||
#android.branch = master
|
||||
|
@ -101,6 +108,17 @@ fullscreen = 1
|
|||
# (list) Android additionnal libraries to copy into libs/armeabi
|
||||
#android.add_libs_armeabi = libs/android/*.so
|
||||
|
||||
# (bool) Indicate whether the screen should stay on
|
||||
# Don't forget to add the WAKE_LOCK permission if you set this to True
|
||||
#android.wakelock = False
|
||||
|
||||
# (list) Android application meta-data to set (key=value format)
|
||||
#android.meta_data =
|
||||
|
||||
# (list) Android library project to add (will be added in the
|
||||
# project.properties automatically.)
|
||||
#android.library_references =
|
||||
|
||||
#
|
||||
# iOS specific
|
||||
#
|
||||
|
|
|
@ -72,7 +72,7 @@ class Target(object):
|
|||
for item in result:
|
||||
command, args = item[0], item[1:]
|
||||
if not hasattr(self, 'cmd_{0}'.format(command)):
|
||||
self.buildozer.error('Unknow command {0}'.format(command))
|
||||
self.buildozer.error('Unknown command {0}'.format(command))
|
||||
exit(1)
|
||||
|
||||
func = getattr(self, 'cmd_{0}'.format(command))
|
||||
|
@ -107,3 +107,6 @@ class Target(object):
|
|||
def cmd_run(self, *args):
|
||||
self.buildozer.prepare_for_build()
|
||||
|
||||
def cmd_serve(self, *args):
|
||||
self.buildozer.cmd_serve()
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ Android target, based on python-for-android project
|
|||
ANDROID_API = '14'
|
||||
ANDROID_MINAPI = '8'
|
||||
ANDROID_SDK_VERSION = '21'
|
||||
ANDROID_NDK_VERSION = '8e'
|
||||
ANDROID_NDK_VERSION = '9'
|
||||
APACHE_ANT_VERSION = '1.8.4'
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ from sys import platform, executable
|
|||
from buildozer import BuildozerException
|
||||
from buildozer.target import Target
|
||||
from os import environ
|
||||
from os.path import join, realpath, expanduser, basename
|
||||
from os.path import join, realpath, expanduser, basename, relpath
|
||||
from shutil import copyfile
|
||||
from glob import glob
|
||||
|
||||
|
@ -69,7 +69,7 @@ class TargetAndroid(Target):
|
|||
version = self.buildozer.config.getdefault(
|
||||
'app', 'android.ndk', self.android_ndk_version)
|
||||
return join(self.buildozer.global_platform_dir,
|
||||
'android-ndk-{0}'.format(version))
|
||||
'android-ndk-r{0}'.format(version))
|
||||
|
||||
@property
|
||||
def apache_ant_dir(self):
|
||||
|
@ -135,6 +135,11 @@ class TargetAndroid(Target):
|
|||
permissions = self.buildozer.config.getlist(
|
||||
'app', 'android.permissions', [])
|
||||
for permission in permissions:
|
||||
# no check on full named permission
|
||||
# like com.google.android.providers.gsf.permission.READ_GSERVICES
|
||||
if '.' in permission:
|
||||
continue
|
||||
permission = permission.upper()
|
||||
if permission not in available_permissions:
|
||||
errors.append(
|
||||
'[app] "android.permission" contain an unknown'
|
||||
|
@ -246,9 +251,10 @@ class TargetAndroid(Target):
|
|||
|
||||
self.buildozer.info('Android NDK is missing, downloading')
|
||||
if platform in ('win32', 'cygwin'):
|
||||
#FIXME find a way of checking 32/64 bits os (not sys.maxint)
|
||||
# Checking of 32/64 bits at Windows from: http://stackoverflow.com/a/1405971/798575
|
||||
import struct
|
||||
archive = 'android-ndk-r{0}-windows-{1}.zip'
|
||||
is_64 = False
|
||||
is_64 = (8*struct.calcsize("P") == 64)
|
||||
elif platform in ('darwin', ):
|
||||
archive = 'android-ndk-r{0}-darwin-{1}.tar.bz2'
|
||||
is_64 = (os.uname()[4] == 'x86_64')
|
||||
|
@ -301,10 +307,10 @@ class TargetAndroid(Target):
|
|||
cmd('git clean -dxf', cwd=pa_dir)
|
||||
cmd('git pull origin master', cwd=pa_dir)
|
||||
|
||||
source = self.buildozer.config.getdefault('app', 'android.branch')
|
||||
if source:
|
||||
cmd('git checkout --track -b %s origin/%s' % (source, source),
|
||||
cwd=pa_dir)
|
||||
source = self.buildozer.config.getdefault('app', 'android.branch')
|
||||
if source:
|
||||
cmd('git checkout %s' % (source),
|
||||
cwd=pa_dir)
|
||||
|
||||
self._install_apache_ant()
|
||||
self._install_android_sdk()
|
||||
|
@ -316,10 +322,11 @@ class TargetAndroid(Target):
|
|||
self.check_configuration_tokens()
|
||||
|
||||
self.buildozer.environ.update({
|
||||
'PACKAGES_PATH': self.buildozer.global_packages_dir,
|
||||
'ANDROIDSDK': self.android_sdk_dir,
|
||||
'ANDROIDNDK': self.android_ndk_dir,
|
||||
'ANDROIDAPI': self.android_api,
|
||||
'ANDROIDNDKVER': self.android_ndk_version})
|
||||
'ANDROIDNDKVER': 'r{}'.format(self.android_ndk_version)})
|
||||
|
||||
def get_available_packages(self):
|
||||
available_modules = self.buildozer.cmd(
|
||||
|
@ -338,7 +345,8 @@ class TargetAndroid(Target):
|
|||
# we need to extract the requirements that python-for-android knows
|
||||
# about
|
||||
available_modules = self.get_available_packages()
|
||||
android_requirements = [x for x in app_requirements if x in
|
||||
onlyname = lambda x: x.split('==')[0]
|
||||
android_requirements = [x for x in app_requirements if onlyname(x) in
|
||||
available_modules]
|
||||
|
||||
need_compile = 0
|
||||
|
@ -353,8 +361,13 @@ class TargetAndroid(Target):
|
|||
|
||||
modules_str = ' '.join(android_requirements)
|
||||
cmd = self.buildozer.cmd
|
||||
self.buildozer.debug('Clean and build python-for-android')
|
||||
cmd('git clean -dxf', cwd=self.pa_dir)
|
||||
cmd('./distribute.sh -m "{0}"'.format(modules_str), cwd=self.pa_dir)
|
||||
self.buildozer.debug('Remove temporary build files')
|
||||
self.buildozer.rmdir(join(self.pa_dir, 'build'))
|
||||
self.buildozer.rmdir(join(self.pa_dir, '.packages'))
|
||||
self.buildozer.rmdir(join(self.pa_dir, 'src', 'jni', 'obj', 'local'))
|
||||
self.buildozer.info('Distribution compiled.')
|
||||
|
||||
# ensure we will not compile again
|
||||
|
@ -390,17 +403,26 @@ class TargetAndroid(Target):
|
|||
'Failed to find libs_armeabi files: {}'.format(
|
||||
pattern))
|
||||
|
||||
# update the project.properties libraries references
|
||||
self._update_libraries_references(dist_dir)
|
||||
|
||||
# add src files
|
||||
self._add_java_src(dist_dir)
|
||||
|
||||
# build the app
|
||||
build_cmd = (
|
||||
'{python} build.py --name {name}'
|
||||
' --version {version}'
|
||||
' --package {package}'
|
||||
' --private {appdir}'
|
||||
' --{storage_type} {appdir}'
|
||||
' --sdk {androidsdk}'
|
||||
' --minsdk {androidminsdk}').format(
|
||||
python=executable,
|
||||
name=quote(config.get('app', 'title')),
|
||||
version=version,
|
||||
package=package,
|
||||
storage_type='private' if config.getbooldefault(
|
||||
'app', 'android.private_storage', True) else 'dir',
|
||||
appdir=self.buildozer.app_dir,
|
||||
androidminsdk=config.getdefault(
|
||||
'app', 'android.minsdk', 8),
|
||||
|
@ -411,7 +433,18 @@ class TargetAndroid(Target):
|
|||
permissions = config.getlist('app',
|
||||
'android.permissions', [])
|
||||
for permission in permissions:
|
||||
build_cmd += ' --permission {0}'.format(permission)
|
||||
# force the latest component to be uppercase
|
||||
permission = permission.split('.')
|
||||
permission[-1] = permission[-1].upper()
|
||||
permission = '.'.join(permission)
|
||||
build_cmd += ' --permission {}'.format(permission)
|
||||
|
||||
# meta-data
|
||||
meta_datas = config.getlistvalues('app', 'android.meta_data', [])
|
||||
for meta in meta_datas:
|
||||
key, value = meta.split('=', 1)
|
||||
meta = '{}={}'.format(key.strip(), value.strip())
|
||||
build_cmd += ' --meta-data "{}"'.format(meta)
|
||||
|
||||
# add extra Java jar files
|
||||
add_jars = config.getlist('app', 'android.add_jars', [])
|
||||
|
@ -457,6 +490,11 @@ class TargetAndroid(Target):
|
|||
if not fullscreen:
|
||||
build_cmd += ' --window'
|
||||
|
||||
# wakelock ?
|
||||
wakelock = config.getbooldefault('app', 'android.wakelock', False)
|
||||
if wakelock:
|
||||
build_cmd += ' --wakelock'
|
||||
|
||||
# intent filters
|
||||
intent_filters = config.getdefault('app',
|
||||
'android.manifest.intent_filters', '')
|
||||
|
@ -489,6 +527,58 @@ class TargetAndroid(Target):
|
|||
self.buildozer.state['android:latestapk'] = apk
|
||||
self.buildozer.state['android:latestmode'] = self.build_mode
|
||||
|
||||
def _update_libraries_references(self, dist_dir):
|
||||
# ensure the project.properties exist
|
||||
project_fn = join(dist_dir, 'project.properties')
|
||||
|
||||
if not self.buildozer.file_exists(project_fn):
|
||||
content = ['target=android-{}\n'.format(self.android_api)]
|
||||
else:
|
||||
with open(project_fn) as fd:
|
||||
content = fd.readlines()
|
||||
|
||||
# extract library reference
|
||||
references = []
|
||||
for line in content[:]:
|
||||
if not line.startswith('android.library.reference.'):
|
||||
continue
|
||||
content.remove(line)
|
||||
|
||||
# convert our references to relative path
|
||||
app_references = self.buildozer.config.getlist(
|
||||
'app', 'android.library_references', [])
|
||||
source_dir = realpath(self.buildozer.config.getdefault('app', 'source.dir', '.'))
|
||||
for cref in app_references:
|
||||
# get the full path of the current reference
|
||||
ref = realpath(join(source_dir, cref))
|
||||
if not self.buildozer.file_exists(ref):
|
||||
self.buildozer.error('Invalid library reference (path not found): {}'.format(cref))
|
||||
exit(1)
|
||||
# get a relative path from the project file
|
||||
ref = relpath(ref, dist_dir)
|
||||
# ensure the reference exists
|
||||
references.append(ref)
|
||||
|
||||
# recreate the project.properties
|
||||
with open(project_fn, 'wb') as fd:
|
||||
for line in content:
|
||||
fd.write(line)
|
||||
for index, ref in enumerate(references):
|
||||
fd.write('android.library.reference.{}={}\n'.format(
|
||||
index + 1, ref))
|
||||
|
||||
self.buildozer.debug('project.properties updated')
|
||||
|
||||
def _add_java_src(self, dist_dir):
|
||||
print '_add_java_src()'
|
||||
java_src = self.buildozer.config.getlist('app', 'android.add_src', [])
|
||||
src_dir = join(dist_dir, 'src')
|
||||
for pattern in java_src:
|
||||
for fn in glob(expanduser(pattern.strip())):
|
||||
print 'match file', fn
|
||||
last_component = basename(fn)
|
||||
self.buildozer.file_copytree(fn, join(src_dir, last_component))
|
||||
|
||||
@property
|
||||
def serials(self):
|
||||
if hasattr(self, '_serials'):
|
||||
|
|
Loading…
Add table
Reference in a new issue