diff --git a/build.py b/build.py
index f42b1191..a7b09139 100755
--- a/build.py
+++ b/build.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# build.py - part of the FDroid server tools
@@ -30,6 +30,8 @@ from xml.dom.minidom import Document
from optparse import OptionParser
import common
+from common import BuildException
+from common import VCSException
#Read configuration...
execfile('config.py')
@@ -46,13 +48,23 @@ parser.add_option("-p", "--package", default=None,
# Get all apps...
apps = common.read_metadata(options.verbose)
-output_dir = "repo"
-tmp_dir = "tmp"
-if not os.path.isdir('tmp'):
- os.makedirs('tmp')
+failed_apps = {}
+build_succeeded = []
-if not os.path.isdir('build'):
- os.makedirs('build')
+output_dir = 'repo'
+if not os.path.isdir(output_dir):
+ print "Creating output directory"
+ os.makedirs(output_dir)
+
+tmp_dir = 'tmp'
+if not os.path.isdir(tmp_dir):
+ print "Creating temporary directory"
+ os.makedirs(tmp_dir)
+
+build_dir = 'build'
+if not os.path.isdir(build_dir):
+ print "Creating build directory"
+ os.makedirs(build_dir)
for app in apps:
@@ -76,415 +88,413 @@ for app in apps:
for thisbuild in app['builds']:
+ try:
+ dest = os.path.join(output_dir, app['id'] + '_' +
+ thisbuild['vercode'] + '.apk')
+ dest_unsigned = os.path.join(tmp_dir, app['id'] + '_' +
+ thisbuild['vercode'] + '_unsigned.apk')
- dest = os.path.join(output_dir, app['id'] + '_' +
- thisbuild['vercode'] + '.apk')
- dest_unsigned = os.path.join(tmp_dir, app['id'] + '_' +
- thisbuild['vercode'] + '_unsigned.apk')
-
- if os.path.exists(dest):
- print "..version " + thisbuild['version'] + " already exists"
- elif thisbuild['commit'].startswith('!'):
- print ("..skipping version " + thisbuild['version'] + " - " +
- thisbuild['commit'][1:])
- else:
- print "..building version " + thisbuild['version']
-
- if not refreshed_source:
- vcs.refreshlocal()
- refreshed_source = True
-
- # Optionally, the actual app source can be in a subdirectory...
- if thisbuild.has_key('subdir'):
- root_dir = os.path.join(build_dir, thisbuild['subdir'])
+ if os.path.exists(dest):
+ print "..version " + thisbuild['version'] + " already exists"
+ elif thisbuild['commit'].startswith('!'):
+ print ("..skipping version " + thisbuild['version'] + " - " +
+ thisbuild['commit'][1:])
else:
- root_dir = build_dir
+ print "..building version " + thisbuild['version']
- # Get a working copy of the right revision...
- if options.verbose:
- print "Resetting repository to " + thisbuild['commit']
- vcs.reset(thisbuild['commit'])
+ if not refreshed_source:
+ vcs.refreshlocal()
+ refreshed_source = True
- # Initialise submodules if requred...
- if thisbuild.get('submodules', 'no') == 'yes':
- vcs.initsubmodules()
+ # Optionally, the actual app source can be in a subdirectory...
+ if thisbuild.has_key('subdir'):
+ root_dir = os.path.join(build_dir, thisbuild['subdir'])
+ else:
+ root_dir = build_dir
- # Generate (or update) the ant build file, build.xml...
- if (thisbuild.get('update', 'yes') == 'yes' and
- not thisbuild.has_key('maven')):
- parms = [os.path.join(sdk_path, 'tools', 'android'),
- 'update', 'project', '-p', '.']
- parms.append('--subprojects')
- if thisbuild.has_key('target'):
- parms.append('-t')
- parms.append(thisbuild['target'])
- if subprocess.call(parms, cwd=root_dir) != 0:
- print "Failed to update project"
- sys.exit(1)
+ # Get a working copy of the right revision...
+ if options.verbose:
+ print "Resetting repository to " + thisbuild['commit']
+ vcs.reset(thisbuild['commit'])
- # If the app has ant set up to sign the release, we need to switch
- # that off, because we want the unsigned apk...
- for propfile in ('build.properties', 'default.properties'):
- if os.path.exists(os.path.join(root_dir, propfile)):
- if subprocess.call(['sed','-i','s/^key.store/#/',
- propfile], cwd=root_dir) !=0:
- print "Failed to amend %s" % propfile
- sys.exit(1)
+ # Initialise submodules if requred...
+ if thisbuild.get('submodules', 'no') == 'yes':
+ vcs.initsubmodules()
- # Update the local.properties file...
- locprops = os.path.join(root_dir, 'local.properties')
- if os.path.exists(locprops):
- f = open(locprops, 'r')
- props = f.read()
- f.close()
- # Fix old-fashioned 'sdk-location' by copying
- # from sdk.dir, if necessary...
- if thisbuild.get('oldsdkloc', 'no') == "yes":
- sdkloc = re.match(r".*^sdk.dir=(\S+)$.*", props,
- re.S|re.M).group(1)
- props += "\nsdk-location=" + sdkloc + "\n"
- # Add ndk location...
- props+= "\nndk.dir=" + ndk_path + "\n"
- # Add java.encoding if necessary...
- if thisbuild.has_key('encoding'):
- props += "\njava.encoding=" + thisbuild['encoding'] + "\n"
- f = open(locprops, 'w')
- f.write(props)
- f.close()
+ # Generate (or update) the ant build file, build.xml...
+ if (thisbuild.get('update', 'yes') == 'yes' and
+ not thisbuild.has_key('maven')):
+ parms = [os.path.join(sdk_path, 'tools', 'android'),
+ 'update', 'project', '-p', '.']
+ parms.append('--subprojects')
+ if thisbuild.has_key('target'):
+ parms.append('-t')
+ parms.append(thisbuild['target'])
+ if subprocess.call(parms, cwd=root_dir) != 0:
+ raise BuildException("Failed to update project")
- # Insert version code and number into the manifest if necessary...
- if thisbuild.has_key('insertversion'):
- if subprocess.call(['sed','-i','s/' + thisbuild['insertversion'] +
- '/' + thisbuild['version'] +'/g',
- 'AndroidManifest.xml'], cwd=root_dir) !=0:
- print "Failed to amend manifest"
- sys.exit(1)
- if thisbuild.has_key('insertvercode'):
- if subprocess.call(['sed','-i','s/' + thisbuild['insertvercode'] +
- '/' + thisbuild['vercode'] +'/g',
- 'AndroidManifest.xml'], cwd=root_dir) !=0:
- print "Failed to amend manifest"
- sys.exit(1)
+ # If the app has ant set up to sign the release, we need to switch
+ # that off, because we want the unsigned apk...
+ for propfile in ('build.properties', 'default.properties'):
+ if os.path.exists(os.path.join(root_dir, propfile)):
+ if subprocess.call(['sed','-i','s/^key.store/#/',
+ propfile], cwd=root_dir) !=0:
+ raise BuildException("Failed to amend %s" % propfile)
- # Delete unwanted file...
- if thisbuild.has_key('rm'):
- os.remove(os.path.join(build_dir, thisbuild['rm']))
+ # Update the local.properties file...
+ locprops = os.path.join(root_dir, 'local.properties')
+ if os.path.exists(locprops):
+ f = open(locprops, 'r')
+ props = f.read()
+ f.close()
+ # Fix old-fashioned 'sdk-location' by copying
+ # from sdk.dir, if necessary...
+ if thisbuild.get('oldsdkloc', 'no') == "yes":
+ sdkloc = re.match(r".*^sdk.dir=(\S+)$.*", props,
+ re.S|re.M).group(1)
+ props += "\nsdk-location=" + sdkloc + "\n"
+ # Add ndk location...
+ props+= "\nndk.dir=" + ndk_path + "\n"
+ # Add java.encoding if necessary...
+ if thisbuild.has_key('encoding'):
+ props += "\njava.encoding=" + thisbuild['encoding'] + "\n"
+ f = open(locprops, 'w')
+ f.write(props)
+ f.close()
- # Fix apostrophes translation files if necessary...
- if thisbuild.get('fixapos', 'no') == 'yes':
- for root, dirs, files in os.walk(os.path.join(root_dir,'res')):
- for filename in files:
- if filename.endswith('.xml'):
- if subprocess.call(['sed','-i','s@' +
- r"\([^\\]\)'@\1\\'" +
- '@g',
- os.path.join(root, filename)]) != 0:
- print "Failed to amend " + filename
- sys.exit(1)
+ # Insert version code and number into the manifest if necessary...
+ if thisbuild.has_key('insertversion'):
+ if subprocess.call(['sed','-i','s/' + thisbuild['insertversion'] +
+ '/' + thisbuild['version'] +'/g',
+ 'AndroidManifest.xml'], cwd=root_dir) !=0:
+ raise BuildException("Failed to amend manifest")
+ if thisbuild.has_key('insertvercode'):
+ if subprocess.call(['sed','-i','s/' + thisbuild['insertvercode'] +
+ '/' + thisbuild['vercode'] +'/g',
+ 'AndroidManifest.xml'], cwd=root_dir) !=0:
+ raise BuildException("Failed to amend manifest")
- # Fix translation files if necessary...
- if thisbuild.get('fixtrans', 'no') == 'yes':
- for root, dirs, files in os.walk(os.path.join(root_dir,'res')):
- for filename in files:
- if filename.endswith('.xml'):
- f = open(os.path.join(root, filename))
- changed = False
- outlines = []
- for line in f:
- num = 1
- index = 0
- oldline = line
- while True:
- index = line.find("%", index)
- if index == -1:
- break
- next = line[index+1:index+2]
- if next == "s" or next == "d":
- line = (line[:index+1] +
- str(num) + "$" +
- line[index+1:])
- num += 1
- index += 3
- else:
- index += 1
- # We only want to insert the positional arguments
- # when there is more than one argument...
- if oldline != line:
- if num > 2:
- changed = True
- else:
- line = oldline
- outlines.append(line)
- f.close()
- if changed:
- f = open(os.path.join(root, filename), 'w')
- f.writelines(outlines)
+ # Delete unwanted file...
+ if thisbuild.has_key('rm'):
+ os.remove(os.path.join(build_dir, thisbuild['rm']))
+
+ # Fix apostrophes translation files if necessary...
+ if thisbuild.get('fixapos', 'no') == 'yes':
+ for root, dirs, files in os.walk(os.path.join(root_dir,'res')):
+ for filename in files:
+ if filename.endswith('.xml'):
+ if subprocess.call(['sed','-i','s@' +
+ r"\([^\\]\)'@\1\\'" +
+ '@g',
+ os.path.join(root, filename)]) != 0:
+ raise BuildException("Failed to amend " + filename)
+
+ # Fix translation files if necessary...
+ if thisbuild.get('fixtrans', 'no') == 'yes':
+ for root, dirs, files in os.walk(os.path.join(root_dir,'res')):
+ for filename in files:
+ if filename.endswith('.xml'):
+ f = open(os.path.join(root, filename))
+ changed = False
+ outlines = []
+ for line in f:
+ num = 1
+ index = 0
+ oldline = line
+ while True:
+ index = line.find("%", index)
+ if index == -1:
+ break
+ next = line[index+1:index+2]
+ if next == "s" or next == "d":
+ line = (line[:index+1] +
+ str(num) + "$" +
+ line[index+1:])
+ num += 1
+ index += 3
+ else:
+ index += 1
+ # We only want to insert the positional arguments
+ # when there is more than one argument...
+ if oldline != line:
+ if num > 2:
+ changed = True
+ else:
+ line = oldline
+ outlines.append(line)
f.close()
+ if changed:
+ f = open(os.path.join(root, filename), 'w')
+ f.writelines(outlines)
+ f.close()
- # Run a pre-build command if one is required...
- if thisbuild.has_key('prebuild'):
- if subprocess.call(thisbuild['prebuild'],
- cwd=root_dir, shell=True) != 0:
- print "Error running pre-build command"
- sys.exit(1)
+ # Run a pre-build command if one is required...
+ if thisbuild.has_key('prebuild'):
+ if subprocess.call(thisbuild['prebuild'],
+ cwd=root_dir, shell=True) != 0:
+ raise BuildException("Error running pre-build command")
- # Apply patches if any
- if 'patch' in thisbuild:
- for patch in thisbuild['patch'].split(';'):
- print "Applying " + patch
- patch_path = os.path.join('metadata', app['id'], patch)
- if subprocess.call(['patch', '-p1',
- '-i', os.path.abspath(patch_path)], cwd=build_dir) != 0:
- print "Failed to apply patch %s" % patch_path
- sys.exit(1)
+ # Apply patches if any
+ if 'patch' in thisbuild:
+ for patch in thisbuild['patch'].split(';'):
+ print "Applying " + patch
+ patch_path = os.path.join('metadata', app['id'], patch)
+ if subprocess.call(['patch', '-p1',
+ '-i', os.path.abspath(patch_path)], cwd=build_dir) != 0:
+ raise BuildException("Failed to apply patch %s" % patch_path)
- # Special case init functions for funambol...
- if thisbuild.get('initfun', 'no') == "yes":
+ # Special case init functions for funambol...
+ if thisbuild.get('initfun', 'no') == "yes":
- if subprocess.call(['sed','-i','s@' +
- '