Conflicts:
	buildozer/__init__.py
	buildozer/targets/android.py
This commit is contained in:
Bob the Hamster 2013-05-06 12:54:36 -07:00
commit 4ccdf18ec3
6 changed files with 164 additions and 30 deletions

View file

@ -1,4 +0,0 @@
buildozer
=========
Generic Python packager for Android / iOS and Desktop

View file

@ -1,7 +1,7 @@
Buildozer
=========
THIS IS A WORK IN PROGRESS, DO NOT USE.
This tool is currently in alpha.
Buildozer is a tool for creating application packages easily.

View file

@ -66,6 +66,7 @@ class Buildozer(object):
self.config = SafeConfigParser()
self.config.getlist = self._get_config_list
self.config.getdefault = self._get_config_default
self.config.getbooldefault = self._get_config_bool
if exists(filename):
self.config.read(filename)
@ -289,6 +290,10 @@ class Buildozer(object):
adderror('[app] "version.filename" is missing'
', required by "version.regex"')
orientation = get('app', 'orientation', 'landscape')
if orientation not in ('landscape', 'portrait', 'all'):
adderror('[app] "orientation" have an invalid value')
if errors:
self.error('{0} error(s) found in the buildozer.spec'.format(
len(errors)))
@ -572,10 +577,17 @@ class Buildozer(object):
'''
return re.sub('[^a-zA-Z0-9_\-]', '_', name)
@property
def root_dir(self):
return realpath(join(dirname(self.specfilename)))
@property
def buildozer_dir(self):
return realpath(join(
dirname(self.specfilename), '.buildozer'))
return join(self.root_dir, '.buildozer')
@property
def bin_dir(self):
return join(self.root_dir, 'bin')
@property
def platform_dir(self):
@ -585,11 +597,6 @@ class Buildozer(object):
def app_dir(self):
return join(self.buildozer_dir, self.targetname, 'app')
@property
def bin_dir(self):
return realpath(join(
dirname(self.specfilename), 'bin'))
@property
def applibs_dir(self):
return join(self.buildozer_dir, 'applibs')
@ -762,10 +769,10 @@ class Buildozer(object):
def _get_config_list(self, section, token, default=None):
# monkey-patch method for ConfigParser
# get a key as a list of string, seperated from the comma
strvalue = self.config.getdefault(section, token, '')
if not strvalue:
return []
values = strvalue.split(',')
values = self.config.getdefault(section, token, '')
if not values:
return default
values = values.split(',')
if not values:
return default
return [x.strip() for x in values]
@ -779,6 +786,14 @@ class Buildozer(object):
return default
return self.config.get(section, token)
def _get_config_bool(self, section, token, default=False):
# monkey-patch method for ConfigParser
# get a key in a section, or the default
if not self.config.has_section(section):
return default
if not self.config.has_option(section, token):
return default
return self.config.getboolean(section, token)
class BuildozerRemote(Buildozer):
def run_command(self, args):

View file

@ -26,7 +26,7 @@ version.filename = %(source.dir)s/main.py
# version = 1.2.0
# (list) Application requirements
requirements = twisted,kivy
requirements = kivy
# (str) Presplash of the application
#presplash.filename = %(source.dir)s/data/presplash.png
@ -34,6 +34,13 @@ requirements = twisted,kivy
# (str) Icon of the application
#icon.filename = %(source.dir)s/data/icon.png
# (str) Supported orientation (one of landscape, portrait or all)
orientation = landscape
# (bool) Indicate if the application should be fullscreen or not
fullscreen = 1
#
# Android specific
#
@ -62,6 +69,9 @@ requirements = twisted,kivy
# (str) Android entry point, default is ok for Kivy-based app
#android.entrypoint = org.renpy.android.PythonActivity
# (str) python-for-android branch to use, if not master, useful to try
# not yet merged features.
#android.branch = master
#
# iOS specific

View file

@ -19,6 +19,7 @@ import traceback
from pipes import quote
from sys import platform, executable
from buildozer.target import Target
from os import environ
from os.path import join, realpath, expanduser
from shutil import copyfile
@ -277,7 +278,7 @@ class TargetAndroid(Target):
cmd('git clean -dxf', cwd=pa_dir)
cmd('git pull origin master', cwd=pa_dir)
source = self.buildozer.config.get('app', 'android.branch')
source = self.buildozer.config.getdefault('app', 'android.branch')
if source:
cmd('git checkout --track -b %s origin/%s' % (source, source),
cwd=pa_dir)
@ -377,12 +378,24 @@ class TargetAndroid(Target):
# add presplash
presplash = config.getdefault('app', 'presplash.filename', '')
if presplash:
build_cmd += ' --presplash {}'.format(join(self.buildozer.app_dir, '..', '..', '..', presplash))
build_cmd += ' --presplash {}'.format(join(self.buildozer.root_dir,
presplash))
# add icon
icon = config.getdefault('app', 'icon.filename', '')
if icon:
build_cmd += ' --icon {}'.format(join(self.buildozer.app_dir, '..', '..', '..', icon))
build_cmd += ' --icon {}'.format(join(self.buildozer.root_dir, icon))
# add orientation
orientation = config.getdefault('app', 'orientation', 'landscape')
if orientation == 'all':
orientation = 'sensor'
build_cmd += ' --orientation {}'.format(orientation)
# fullscreen ?
fullscreen = config.getbooldefault('app', 'fullscreen', True)
if not fullscreen:
build_cmd += ' --window'
# build only in debug right now.
if self.build_mode == 'debug':
@ -409,6 +422,21 @@ class TargetAndroid(Target):
self.buildozer.state['android:latestapk'] = apk
self.buildozer.state['android:latestmode'] = self.build_mode
@property
def serials(self):
if hasattr(self, '_serials'):
return self._serials
serial = environ.get('ANDROID_SERIAL')
if serial:
return [serial]
l = self.buildozer.cmd('adb devices',
get_stdout=True)[0].splitlines()[1:-1]
serials = []
for serial in l:
serials.append(serial.split()[0])
self._serials = serials
return serials
def cmd_deploy(self, *args):
super(TargetAndroid, self).cmd_deploy(*args)
state = self.buildozer.state
@ -428,10 +456,14 @@ class TargetAndroid(Target):
'Unable to found the latest APK. Please run "debug" again.')
# push on the device
for serial in self.serials:
self.buildozer.environ['ANDROID_SERIAL'] = serial
self.buildozer.info('Deploy on {}'.format(serial))
self.buildozer.cmd('{0} install -r {1}'.format(
self.adb_cmd, full_apk), cwd=self.buildozer.global_platform_dir)
self.buildozer.environ.pop('ANDROID_SERIAL', None)
self.buildozer.info('Application pushed on the device.')
self.buildozer.info('Application pushed.')
def cmd_run(self, *args):
super(TargetAndroid, self).cmd_run(*args)
@ -440,20 +472,30 @@ class TargetAndroid(Target):
'app', 'android.entrypoint', 'org.renpy.android.PythonActivity')
package = self._get_package()
# push on the device
for serial in self.serials:
self.buildozer.environ['ANDROID_SERIAL'] = serial
self.buildozer.info('Run on {}'.format(serial))
self.buildozer.cmd(
'{adb} shell am start -n {package}/{entry} -a {entry}'.format(
adb=self.adb_cmd, package=package, entry=entrypoint),
cwd=self.buildozer.global_platform_dir)
self.buildozer.environ.pop('ANDROID_SERIAL', None)
self.buildozer.info('Application started on the device.')
self.buildozer.info('Application started.')
def cmd_logcat(self, *args):
'''Show the log from the device
'''
self.check_requirements()
serial = self.serials[0:]
if not serial:
return
self.buildozer.environ['ANDROID_SERIAL'] = serial[0]
self.buildozer.cmd('{adb} logcat'.format(adb=self.adb_cmd),
cwd=self.buildozer.global_platform_dir,
show_output=True)
self.buildozer.environ.pop('ANDROID_SERIAL', None)

View file

@ -8,6 +8,52 @@ from buildozer.target import Target
from os.path import join, basename
from getpass import getpass
PHP_TEMPLATE = '''
<?php
// credits goes to http://jeffreysambells.com/2010/06/22/ios-wireless-app-distribution
$ipas = glob('*.ipa');
$provisioningProfiles = glob('*.mobileprovision');
$plists = glob('*.plist');
$sr = stristr( $_SERVER['SCRIPT_URI'], '.php' ) === false ?
$_SERVER['SCRIPT_URI'] : dirname($_SERVER['SCRIPT_URI']) . '/';
$provisioningProfile = $sr . $provisioningProfiles[0];
$ipa = $sr . $ipas[0];
$itmsUrl = urlencode( $sr . 'index.php?plist=' . str_replace( '.plist', '', $plists[0] ) );
if ($_GET['plist']) {
$plist = file_get_contents( dirname(__FILE__)
. DIRECTORY_SEPARATOR
. preg_replace( '/![A-Za-z0-9-_]/i', '', $_GET['plist']) . '.plist' );
$plist = str_replace('_URL_', $ipa, $plist);
header('content-type: application/xml');
echo $plist;
die();
}
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Install {appname}</title>
<style type="text/css">
li { padding: 1em; }
</style>
</head>
<body>
<ul>
<li><a href="<? echo $provisioningProfile; ?>">Install Team Provisioning File</a></li>
<li><a href="itms-services://?action=download-manifest&url=<? echo $itmsUrl; ?>">
Install Application</a></li>
</ul>
</body>
</html>
'''
class TargetIos(Target):
def check_requirements(self):
@ -17,6 +63,13 @@ class TargetIos(Target):
checkbin('Xcode xcodebuild', 'xcodebuild')
checkbin('Xcode xcode-select', 'xcode-select')
checkbin('Git git', 'git')
checkbin('Cython', 'cython')
checkbin('Mercurial', 'hg')
checkbin('Cython cython', 'cython')
checkbin('pkg-config', 'pkg-config')
checkbin('autoconf', 'autoconf')
checkbin('automake', 'automake')
checkbin('libtool', 'libtool')
self.buildozer.debug('Check availability of a iPhone SDK')
sdk = cmd('xcodebuild -showsdks | fgrep "iphoneos" |'
@ -72,7 +125,8 @@ class TargetIos(Target):
self._unlock_keychain()
# create the project
app_name = self.buildozer.namify(self.buildozer.config.get('app', 'title'))
app_name = self.buildozer.namify(self.buildozer.config.get('app',
'package.name'))
self.app_project_dir = join(self.ios_dir, 'app-{0}'.format(app_name.lower()))
if not self.buildozer.file_exists(self.app_project_dir):
@ -106,7 +160,7 @@ class TargetIos(Target):
plistlib.writePlist(plist, plist_rfn)
mode = 'Debug' if self.build_mode == 'debug' else 'Release'
self.buildozer.cmd('xcodebuild -configuration {}'.format(mode),
self.buildozer.cmd('xcodebuild -configuration {} clean build'.format(mode),
cwd=self.app_project_dir)
ios_app_dir = 'app-{app_lower}/build/{mode}-iphoneos/{app_lower}.app'.format(
app_lower=app_name.lower(), mode=mode)
@ -138,6 +192,8 @@ class TargetIos(Target):
self.buildozer.state['ios:latestipa'] = ipa
self.buildozer.state['ios:latestmode'] = self.build_mode
self._create_index()
def cmd_deploy(self, *args):
super(TargetIos, self).cmd_deploy(*args)
self._run_fruitstrap(gdb=False)
@ -146,6 +202,17 @@ class TargetIos(Target):
super(TargetIos, self).cmd_run(*args)
self._run_fruitstrap(gdb=True)
def cmd_xcode(self, *args):
'''Open the xcode project.
'''
app_name = self.buildozer.namify(self.buildozer.config.get('app',
'package.name'))
app_name = app_name.lower()
ios_dir = ios_dir = join(self.buildozer.platform_dir, 'kivy-ios')
self.buildozer.cmd('open {}.xcodeproj'.format(
app_name), cwd=join(ios_dir, 'app-{}'.format(app_name)))
def _run_fruitstrap(self, gdb=False):
state = self.buildozer.state
if 'ios:latestappdir' not in state:
@ -210,6 +277,10 @@ class TargetIos(Target):
icon_fn = join(self.app_project_dir, icon_basename)
return icon_fn
def _create_index(self):
# TODO
pass
def check_configuration_tokens(self):
errors = []
config = self.buildozer.config