import resource
import sys
import tarfile
+import threading
import traceback
import time
import requests
else:
logging.getLogger("paramiko").setLevel(logging.WARN)
- sshinfo = vmtools.get_clean_builder('builder')
+ sshinfo = vmtools.get_clean_builder('builder', options.reset_server)
try:
if not buildserverid:
ftp.chmod('config.py', 0o600)
# Copy over the ID (head commit hash) of the fdroidserver in use...
- subprocess.call('git rev-parse HEAD >' +
- os.path.join(os.getcwd(), 'tmp', 'fdroidserverid'),
- shell=True, cwd=serverpath)
+ with open(os.path.join(os.getcwd(), 'tmp', 'fdroidserverid'), 'wb') as fp:
+ fp.write(subprocess.check_output(['git', 'rev-parse', 'HEAD'],
+ cwd=serverpath))
ftp.put('tmp/fdroidserverid', 'fdroidserverid')
# Copy the metadata - just the file for this app...
logging.info("...getting exit status")
returncode = chan.recv_exit_status()
if returncode != 0:
- raise BuildException(
- "Build.py failed on server for {0}:{1}".format(
- app.id, build.versionName), None if options.verbose else str(output, 'utf-8'))
+ if timeout_event.is_set():
+ message = "Timeout exceeded! Build VM force-stopped for {0}:{1}"
+ else:
+ message = "Build.py failed on server for {0}:{1}"
+ raise BuildException(message.format(app.id, build.versionName),
+ None if options.verbose else str(output, 'utf-8'))
# Retreive logs...
toolsversion_log = common.get_toolsversion_logname(app, build)
p = FDroidPopen(cmd, cwd=root_dir)
- elif bmethod == 'kivy':
- pass
-
elif bmethod == 'buildozer':
pass
bindir = os.path.join(root_dir, 'target')
- elif bmethod == 'kivy':
- logging.info("Building Kivy project...")
-
- spec = os.path.join(root_dir, 'buildozer.spec')
- if not os.path.exists(spec):
- raise BuildException("Expected to find buildozer-compatible spec at {0}"
- .format(spec))
-
- defaults = {'orientation': 'landscape', 'icon': '',
- 'permissions': '', 'android.api': "18"}
- bconfig = ConfigParser(defaults, allow_no_value=True)
- bconfig.read(spec)
-
- distdir = os.path.join('python-for-android', 'dist', 'fdroid')
- if os.path.exists(distdir):
- shutil.rmtree(distdir)
-
- modules = bconfig.get('app', 'requirements').split(',')
-
- cmd = 'ANDROIDSDK=' + config['sdk_path']
- cmd += ' ANDROIDNDK=' + ndk_path
- cmd += ' ANDROIDNDKVER=' + build.ndk
- cmd += ' ANDROIDAPI=' + str(bconfig.get('app', 'android.api'))
- cmd += ' VIRTUALENV=virtualenv'
- cmd += ' ./distribute.sh'
- cmd += ' -m ' + "'" + ' '.join(modules) + "'"
- cmd += ' -d fdroid'
- p = subprocess.Popen(cmd, cwd='python-for-android', shell=True)
- if p.returncode != 0:
- raise BuildException("Distribute build failed")
-
- cid = bconfig.get('app', 'package.domain') + '.' + bconfig.get('app', 'package.name')
- if cid != app.id:
- raise BuildException("Package ID mismatch between metadata and spec")
-
- orientation = bconfig.get('app', 'orientation', 'landscape')
- if orientation == 'all':
- orientation = 'sensor'
-
- cmd = ['./build.py'
- '--dir', root_dir,
- '--name', bconfig.get('app', 'title'),
- '--package', app.id,
- '--version', bconfig.get('app', 'version'),
- '--orientation', orientation
- ]
-
- perms = bconfig.get('app', 'permissions')
- for perm in perms.split(','):
- cmd.extend(['--permission', perm])
-
- if config.get('app', 'fullscreen') == 0:
- cmd.append('--window')
-
- icon = bconfig.get('app', 'icon.filename')
- if icon:
- cmd.extend(['--icon', os.path.join(root_dir, icon)])
-
- cmd.append('release')
- p = FDroidPopen(cmd, cwd=distdir)
-
elif bmethod == 'buildozer':
logging.info("Building Kivy project using buildozer...")
raise BuildException('Failed to find output')
src = m.group(1)
src = os.path.join(bindir, src) + '.apk'
- elif omethod == 'kivy':
- src = os.path.join('python-for-android', 'dist', 'default', 'bin',
- '{0}-{1}-release.apk'.format(
- bconfig.get('app', 'title'),
- bconfig.get('app', 'version')))
elif omethod == 'buildozer':
src = None
return True
+def force_halt_build(timeout):
+ """Halt the currently running Vagrant VM, to be called from a Timer"""
+ logging.error(_('Force halting build after {0} sec timeout!').format(timeout))
+ timeout_event.set()
+ vm = vmtools.get_build_vm('builder')
+ vm.halt()
+
+
def parse_commandline():
"""Parse the command line. Returns options, parser."""
help=_("Test mode - put output in the tmp directory only, and always build, even if the output already exists."))
parser.add_argument("--server", action="store_true", default=False,
help=_("Use build server"))
- parser.add_argument("--resetserver", action="store_true", default=False,
+ parser.add_argument("--reset-server", action="store_true", default=False,
help=_("Reset and create a brand new build server, even if the existing one appears to be ok."))
parser.add_argument("--on-server", dest="onserver", action="store_true", default=False,
help=_("Specify that we're running on the build server"))
buildserverid = None
fdroidserverid = None
start_timestamp = time.gmtime()
+timeout_event = threading.Event()
def main():
if config['build_server_always']:
options.server = True
- if options.resetserver and not options.server:
- parser.error("option %s: Using --resetserver without --server makes no sense" % "resetserver")
+ if options.reset_server and not options.server:
+ parser.error("option %s: Using --reset-server without --server makes no sense" % "reset-server")
log_dir = 'logs'
if not os.path.isdir(log_dir):
# Build applications...
failed_apps = {}
build_succeeded = []
- max_apps_per_run = 50
+ # Only build for 36 hours, then stop gracefully.
+ endtime = time.time() + 36 * 60 * 60
+ max_build_time_reached = False
for appid, app in apps.items():
- max_apps_per_run -= 1
- if max_apps_per_run < 1:
- break
first = True
for build in app.builds:
+ if time.time() > endtime:
+ max_build_time_reached = True
+ break
+
+ # Enable watchdog timer (2 hours by default).
+ if build.timeout is None:
+ timeout = 7200
+ else:
+ timeout = int(build.timeout)
+ if options.server and timeout > 0:
+ logging.debug(_('Setting {0} sec timeout for this build').format(timeout))
+ timer = threading.Timer(timeout, force_halt_build, [timeout])
+ timeout_event.clear()
+ timer.start()
+ else:
+ timer = None
+
wikilog = None
build_starttime = common.get_wiki_timestamp()
tools_version_log = ''
except Exception as e:
logging.error("Error while attempting to publish build log: %s" % e)
+ if timer:
+ timer.cancel() # kill the watchdog timer
+
+ if max_build_time_reached:
+ logging.info("Stopping after global build timeout...")
+ break
+
for app in build_succeeded:
logging.info("success: %s" % (app.id))
for app in build_succeeded:
logging.info("Need to sign the app before we can install it.")
- subprocess.call("fdroid publish {0}".format(app.id), shell=True)
+ subprocess.call("fdroid publish {0}".format(app.id))
apk_path = None