import os
import pathlib
+import re
import requests
import stat
import sys
+import shutil
import subprocess
-import time
+import vagrant
import hashlib
import yaml
+import json
+import logging
from clint.textui import progress
from optparse import OptionParser
+import fdroidserver.tail
+import fdroidserver.vmtools
-if not os.path.exists('makebuildserver') and not os.path.exists('buildserver'):
- print('This must be run as ./makebuildserver in fdroidserver.git!')
- sys.exit(1)
-
-
-def vagrant(params, cwd=None, printout=False):
- """Run vagrant.
-
- :param: list of parameters to pass to vagrant
- :cwd: directory to run in, or None for current directory
- :printout: True to print output in realtime, False to just
- return it
- :returns: (ret, out) where ret is the return code, and out
- is the stdout (and stderr) from vagrant
- """
- p = subprocess.Popen(['vagrant'] + params, cwd=cwd,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
- universal_newlines=True)
- out = ''
- if printout:
- while True:
- line = p.stdout.readline()
- if len(line) == 0:
- break
- print(line.rstrip())
- out += line
- p.wait()
- else:
- out = p.communicate()[0]
- return (p.returncode, out)
-
-
-boxfile = 'buildserver.box'
-serverdir = 'buildserver'
-
parser = OptionParser()
-parser.add_option("-v", "--verbose", action="store_true", default=False,
+parser.add_option('-v', '--verbose', action="count", dest='verbosity', default=1,
help="Spew out even more information than normal")
+parser.add_option('-q', action='store_const', const=0, dest='verbosity')
parser.add_option("-c", "--clean", action="store_true", default=False,
help="Build from scratch, rather than attempting to update the existing server")
+parser.add_option('--skip-cache-update', action="store_true", default=False,
+ help="""Skip downloading and checking cache."""
+ """This assumes that the cache is already downloaded completely.""")
+parser.add_option('--keep-box-file', action="store_true", default=False,
+ help="""Box file will not be deleted after adding it to box storage"""
+ """ (KVM-only).""")
options, args = parser.parse_args()
+logger = logging.getLogger('fdroidserver-makebuildserver')
+if options.verbosity >= 2:
+ logging.basicConfig(format='%(message)s', level=logging.DEBUG)
+ logger.setLevel(logging.DEBUG)
+elif options.verbosity == 1:
+ logging.basicConfig(format='%(message)s', level=logging.INFO)
+ logger.setLevel(logging.INFO)
+elif options.verbosity <= 0:
+ logging.basicConfig(format='%(message)s', level=logging.WARNING)
+ logger.setLevel(logging.WARNING)
+
+
+if not os.path.exists('makebuildserver') and not os.path.exists('buildserver'):
+ logger.critical('This must be run as ./makebuildserver in fdroidserver.git!')
+ sys.exit(1)
+
+tail = None
+
# set up default config
cachedir = os.path.join(os.getenv('HOME'), '.cache', 'fdroidserver')
+logger.debug('cachedir set to: %s', cachedir)
+
config = {
'basebox': 'jessie64',
'baseboxurl': [
],
'debian_mirror': 'http://http.debian.net/debian/',
'apt_package_cache': False,
+ 'copy_caches_from_host': False,
'boot_timeout': 600,
'cachedir': cachedir,
'cpus': 1,
except subprocess.CalledProcessError as e:
virt = 'none'
if virt == 'qemu' or virt == 'kvm' or virt == 'bochs':
- print('Running in a VM guest, defaulting to QEMU/KVM via libvirt')
+ logger.info('Running in a VM guest, defaulting to QEMU/KVM via libvirt')
config['vm_provider'] = 'libvirt'
elif virt != 'none':
- print('Running in an unsupported VM guest (' + virt + ')!')
+ logger.info('Running in an unsupported VM guest (%s)!', virt)
+ logger.debug('detected virt: %s', virt)
# load config file, if present
if os.path.exists('makebuildserver.config.py'):
exec(compile(open('makebs.config.py').read(), 'makebs.config.py', 'exec'), config)
if '__builtins__' in config:
del(config['__builtins__']) # added by compile/exec
-
-if os.path.exists(boxfile):
- os.remove(boxfile)
-
-if options.clean:
- vagrant(['destroy', '-f'], cwd=serverdir, printout=options.verbose)
- if config['vm_provider'] == 'libvirt':
- subprocess.call(['virsh', 'undefine', 'buildserver_default'])
- subprocess.call(['virsh', 'vol-delete', '/var/lib/libvirt/images/buildserver_default.img'])
+logger.debug("makebuildserver.config.py parsed -> %s", json.dumps(config, indent=4, sort_keys=True))
# Update cached files.
cachedir = config['cachedir']
if not os.path.exists(cachedir):
os.makedirs(cachedir, 0o755)
+ logger.debug('created cachedir %s because it did not exists.', cachedir)
if config['vm_provider'] == 'libvirt':
tmp = cachedir
while tmp != '/':
mode = os.stat(tmp).st_mode
if not (stat.S_IXUSR & mode and stat.S_IXGRP & mode and stat.S_IXOTH & mode):
- print('ERROR:', tmp, 'will not be accessible to the VM! To fix, run:')
- print(' chmod a+X', tmp)
+ logger.critical('ERROR: %s will not be accessible to the VM! To fix, run:', tmp)
+ logger.critical(' chmod a+X %s', tmp)
sys.exit(1)
tmp = os.path.dirname(tmp)
+ logger.debug('cache dir %s is accessible for libvirt vm.', cachedir)
if config['apt_package_cache']:
config['aptcachedir'] = cachedir + '/apt/archives'
+ logger.debug('aptcachedir is set to %s', config['aptcachedir'])
+ aptcachelock = os.path.join(config['aptcachedir'], 'lock')
+ if os.path.isfile(aptcachelock):
+ logger.info('apt cache dir is locked, removing lock')
+ os.remove(aptcachelock)
+ aptcachepartial = os.path.join(config['aptcachedir'], 'partial')
+ if os.path.isdir(aptcachepartial):
+ logger.info('removing partial downloads from apt cache dir')
+ shutil.rmtree(aptcachepartial)
cachefiles = [
- ('https://dl.google.com/android/repository/tools_r25.2.3-linux.zip',
- '1b35bcb94e9a686dff6460c8bca903aa0281c6696001067f34ec00093145b560'),
- ('https://dl.google.com/android/repository/android_m2repository_r44.zip',
- 'fc18547ca5ad18f03d53bbd5abbb07651147f6fc718b99b431d5342b36280a40'),
+ # Don't update sdk tools beyond 25.2.5.
+ # Support for android update project has been removed and there is no replacement.
+ # Until we find a solution for that we need to stay at this revision.
+ ('https://dl.google.com/android/repository/tools_r25.2.5-linux.zip',
+ '577516819c8b5fae680f049d39014ff1ba4af870b687cab10595783e6f22d33e'),
+ ('https://dl.google.com/android/repository/android_m2repository_r47.zip',
+ 'a3f91808dce50c1717737de90c18479ed3a78b147e06985247d138e7ab5123d0'),
('https://dl.google.com/android/repository/android-1.5_r04-linux.zip',
'85b6c8f9797e56aa415d3a282428bb640c96b0acb17c11d41621bb2a5302fe64'),
('https://dl.google.com/android/repository/android-1.6_r03-linux.zip',
'4b4bcddead3319708275c54c76294707bfaa953d767e34f1a5b599f3edd0076c'),
('https://dl.google.com/android/repository/platform-24_r02.zip',
'f268f5945c6ece7ea95c1c252067280854d2a20da924e22ae4720287df8bdbc9'),
- ('https://dl.google.com/android/repository/platform-25_r01.zip',
- 'da519dc3e07b8cb879265c94f798262c1f90791dfaa8b745d34883891378438e'),
+ ('https://dl.google.com/android/repository/platform-25_r03.zip',
+ '9b742d34590fe73fb7229e34835ecffb1846ca389d9f924f0b2a37de525dc6b8'),
+ ('https://dl.google.com/android/repository/platform-26_r02.zip',
+ '2aafa7d19c5e9c4b643ee6ade3d85ef89dc2f79e8383efdb9baf7fddad74b52a'),
('https://dl.google.com/android/repository/build-tools_r17-linux.zip',
'4c8444972343a19045236f6924bd7f12046287c70dace96ab88b2159c8ec0e74'),
('https://dl.google.com/android/repository/build-tools_r18.0.1-linux.zip',
'671b4e00f5b986c7355507c7024b725a4b4cadf11ca61fa5b1334ec6ea57d94f'),
('https://dl.google.com/android/repository/build-tools_r25.0.2-linux.zip',
'1d7ac9b6def16fb0254ec23c135c02dd9f6908073352a20315a017e4b2a904b0'),
+ ('https://dl.google.com/android/repository/build-tools_r25.0.3-linux.zip',
+ '152c1b187947edd10c65af8b279d40321ecc106106323e53df3608e578042d65'),
+ ('https://dl.google.com/android/repository/build-tools_r26-linux.zip',
+ '7422682f92fb471d4aad4c053c9982a9a623377f9d5e4de7a73cd44ebf2f3c61'),
+ ('https://dl.google.com/android/repository/build-tools_r26.0.1-linux.zip',
+ 'c8617f25a7de2aeb9ddcacf1aeb413e053d5ed5ef4a3f31fe0ce21d4428ee0ea'),
# the binaries that Google uses are here:
# https://android.googlesource.com/platform/tools/external/gradle/+/studio-1.5/
('https://services.gradle.org/distributions/gradle-1.4-bin.zip',
'72d0cd4dcdd5e3be165eb7cd7bbd25cf8968baf400323d9ab1bba622c3f72205'),
('https://services.gradle.org/distributions/gradle-3.4.1-bin.zip',
'db1db193d479cc1202be843f17e4526660cfb0b21b57d62f3a87f88c878af9b2'),
+ ('https://services.gradle.org/distributions/gradle-3.5-bin.zip',
+ '0b7450798c190ff76b9f9a3d02e18b33d94553f708ebc08ebe09bdf99111d110'),
+ ('https://services.gradle.org/distributions/gradle-3.5.1-bin.zip',
+ '8dce35f52d4c7b4a4946df73aa2830e76ba7148850753d8b5e94c5dc325ceef8'),
+ ('https://services.gradle.org/distributions/gradle-4.0-bin.zip',
+ '56bd2dde29ba2a93903c557da1745cafd72cdd8b6b0b83c05a40ed7896b79dfe'),
+ ('https://services.gradle.org/distributions/gradle-4.0.1-bin.zip',
+ 'd717e46200d1359893f891dab047fdab98784143ac76861b53c50dbd03b44fd4'),
+ ('https://services.gradle.org/distributions/gradle-4.0.2-bin.zip',
+ '79ac421342bd11f6a4f404e0988baa9c1f5fabf07e3c6fa65b0c15c1c31dda22'),
+ ('https://services.gradle.org/distributions/gradle-4.1-bin.zip',
+ 'd55dfa9cfb5a3da86a1c9e75bb0b9507f9a8c8c100793ccec7beb6e259f9ed43'),
('https://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin',
'102d6723f67ff1384330d12c45854315d6452d6510286f4e5891e00a5a8f1d5a'),
('https://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64.tar.bz2',
'eafae2d614e5475a3bcfd7c5f201db5b963cc1290ee3e8ae791ff0c66757781e'),
('https://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip',
'3524d7f8fca6dc0d8e7073a7ab7f76888780a22841a6641927123146c3ffd29c'),
+ ('https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip',
+ '0ecc2017802924cf81fffc0f51d342e3e69de6343da892ac9fa1cd79bc106024'),
+ ('https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip',
+ 'f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c'),
('https://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-linux-x64-android-5.7.0.run',
'f7e55b7970e59bdaabb88cb7afc12e9061e933992bda2f076f52600358644586'),
]
return s.hexdigest()
-for srcurl, shasum in cachefiles:
- filename = os.path.basename(srcurl)
- local_filename = os.path.join(cachedir, filename)
-
- if os.path.exists(local_filename):
- local_length = os.path.getsize(local_filename)
+def run_via_vagrant_ssh(v, cmdlist):
+ if (isinstance(cmdlist, str) or isinstance(cmdlist, bytes)):
+ cmd = cmdlist
else:
- local_length = -1
+ cmd = ' '.join(cmdlist)
+ v._run_vagrant_command(['ssh', '-c', cmd])
- resume_header = {}
- download = True
- try:
- r = requests.head(srcurl, allow_redirects=True, timeout=60)
- if r.status_code == 200:
- content_length = int(r.headers.get('content-length'))
+def update_cache(cachedir, cachefiles):
+ for srcurl, shasum in cachefiles:
+ filename = os.path.basename(srcurl)
+ local_filename = os.path.join(cachedir, filename)
+
+ if os.path.exists(local_filename):
+ local_length = os.path.getsize(local_filename)
else:
+ local_length = -1
+
+ resume_header = {}
+ download = True
+
+ try:
+ r = requests.head(srcurl, allow_redirects=True, timeout=60)
+ if r.status_code == 200:
+ content_length = int(r.headers.get('content-length'))
+ else:
+ content_length = local_length # skip the download
+ except requests.exceptions.RequestException as e:
content_length = local_length # skip the download
- except requests.exceptions.RequestException as e:
- content_length = local_length # skip the download
- print(e)
-
- if local_length == content_length:
- download = False
- elif local_length > content_length:
- print('deleting corrupt file from cache: ' + local_filename)
- os.remove(local_filename)
- print("Downloading " + filename + " to cache")
- elif local_length > -1 and local_length < content_length:
- print("Resuming download of " + local_filename)
- resume_header = {'Range': 'bytes=%d-%d' % (local_length, content_length)}
+ logger.warn('%s', e)
+
+ if local_length == content_length:
+ download = False
+ elif local_length > content_length:
+ logger.info('deleting corrupt file from cache: %s', local_filename)
+ os.remove(local_filename)
+ logger.info("Downloading %s to cache", filename)
+ elif local_length > -1 and local_length < content_length:
+ logger.info("Resuming download of %s", local_filename)
+ resume_header = {'Range': 'bytes=%d-%d' % (local_length, content_length)}
+ else:
+ logger.info("Downloading %s to cache", filename)
+
+ if download:
+ r = requests.get(srcurl, headers=resume_header,
+ stream=True, allow_redirects=True)
+ content_length = int(r.headers.get('content-length'))
+ with open(local_filename, 'ab') as f:
+ for chunk in progress.bar(r.iter_content(chunk_size=65536),
+ expected_size=(content_length / 65536) + 1):
+ if chunk: # filter out keep-alive new chunks
+ f.write(chunk)
+
+ v = sha256_for_file(local_filename)
+ if v == shasum:
+ logger.info("\t...shasum verified for %s", local_filename)
+ else:
+ logger.critical("Invalid shasum of '%s' detected for %s", v, local_filename)
+ os.remove(local_filename)
+ sys.exit(1)
+
+
+def debug_log_vagrant_vm(vm_dir, config):
+ if options.verbosity >= 3:
+ _vagrant_dir = os.path.join(vm_dir, '.vagrant')
+ logger.debug('check %s dir exists? -> %r', _vagrant_dir, os.path.isdir(_vagrant_dir))
+ logger.debug('> vagrant status')
+ subprocess.call(['vagrant', 'status'], cwd=vm_dir)
+ logger.debug('> vagrant box list')
+ subprocess.call(['vagrant', 'box', 'list'])
+ if config['vm_provider'] == 'libvirt':
+ logger.debug('> virsh -c qmeu:///system list --all')
+ subprocess.call(['virsh', '-c', 'qemu:///system', 'list', '--all'])
+ domain = 'buildserver_default'
+ logger.debug('> virsh -c qemu:///system snapshot-list %s', domain)
+ subprocess.call(['virsh', '-c', 'qemu:///system', 'snapshot-list', domain])
+
+
+def main():
+ global cachedir, cachefiles, config, tail
+
+ if options.skip_cache_update:
+ logger.info('skipping cache update and verification...')
else:
- print("Downloading " + filename + " to cache")
-
- if download:
- r = requests.get(srcurl, headers=resume_header,
- stream=True, verify=False, allow_redirects=True)
- content_length = int(r.headers.get('content-length'))
- with open(local_filename, 'ab') as f:
- for chunk in progress.bar(r.iter_content(chunk_size=65536),
- expected_size=(content_length / 65536) + 1):
- if chunk: # filter out keep-alive new chunks
- f.write(chunk)
-
- v = sha256_for_file(local_filename)
- if v == shasum:
- print("\t...shasum verified for " + local_filename)
+ update_cache(cachedir, cachefiles)
+
+ local_qt_filename = os.path.join(cachedir, 'qt-opensource-linux-x64-android-5.7.0.run')
+ logger.info("Setting executable bit for %s", local_qt_filename)
+ os.chmod(local_qt_filename, 0o755)
+
+ # use VirtualBox software virtualization if hardware is not available,
+ # like if this is being run in kvm or some other VM platform, like
+ # http://jenkins.debian.net, the values are 'on' or 'off'
+ if sys.platform.startswith('darwin'):
+ # all < 10 year old Macs work, and OSX servers as VM host are very
+ # rare, but this could also be auto-detected if someone codes it
+ config['hwvirtex'] = 'on'
+ logger.info('platform is darwnin -> hwvirtex = \'on\'')
+ elif os.path.exists('/proc/cpuinfo'):
+ with open('/proc/cpuinfo') as f:
+ contents = f.read()
+ if 'vmx' in contents or 'svm' in contents:
+ config['hwvirtex'] = 'on'
+ logger.info('found \'vmx\' or \'svm\' in /proc/cpuinfo -> hwvirtex = \'on\'')
+
+ serverdir = os.path.join(os.getcwd(), 'buildserver')
+ logfilename = os.path.join(serverdir, 'up.log')
+ if not os.path.exists(logfilename):
+ open(logfilename, 'a').close() # create blank file
+ log_cm = vagrant.make_file_cm(logfilename)
+ v = vagrant.Vagrant(root=serverdir, out_cm=log_cm, err_cm=log_cm)
+
+ if options.verbosity >= 2:
+ tail = fdroidserver.tail.Tail(logfilename)
+ tail.start()
+
+ vm = fdroidserver.vmtools.get_build_vm(serverdir, provider=config['vm_provider'])
+ if options.clean:
+ vm.destroy()
+
+ # Check against the existing Vagrantfile.yaml, and if they differ, we
+ # need to create a new box:
+ vf = os.path.join(serverdir, 'Vagrantfile.yaml')
+ writevf = True
+ if os.path.exists(vf):
+ logger.info('Halting %s', serverdir)
+ v.halt()
+ with open(vf, 'r', encoding='utf-8') as f:
+ oldconfig = yaml.load(f)
+ if config != oldconfig:
+ logger.info("Server configuration has changed, rebuild from scratch is required")
+ vm.destroy()
+ else:
+ logger.info("Re-provisioning existing server")
+ writevf = False
else:
- print("Invalid shasum of '" + v + "' detected for " + local_filename)
- os.remove(local_filename)
+ logger.info("No existing server - building from scratch")
+ if writevf:
+ with open(vf, 'w', encoding='utf-8') as f:
+ yaml.dump(config, f)
+
+ if config['vm_provider'] == 'libvirt':
+ found_basebox = False
+ needs_mutate = False
+ for box in v.box_list():
+ if box.name == config['basebox']:
+ found_basebox = True
+ if box.provider != 'libvirt':
+ needs_mutate = True
+ continue
+ if not found_basebox:
+ if isinstance(config['baseboxurl'], str):
+ baseboxurl = config['baseboxurl']
+ else:
+ baseboxurl = config['baseboxurl'][0]
+ logger.info('Adding %s from %s', config['basebox'], baseboxurl)
+ v.box_add(config['basebox'], baseboxurl)
+ needs_mutate = True
+ if needs_mutate:
+ logger.info('Converting %s to libvirt format', config['basebox'])
+ v._call_vagrant_command(['mutate', config['basebox'], 'libvirt'])
+ logger.info('Removing virtualbox format copy of %s', config['basebox'])
+ v.box_remove(config['basebox'], 'virtualbox')
+
+ logger.info("Configuring build server VM")
+ debug_log_vagrant_vm(serverdir, config)
+ try:
+ v.up(provision=True)
+ except fdroidserver.vmtools.FDroidBuildVmException as e:
+ debug_log_vagrant_vm(serverdir, config)
+ logger.exception('could not bring buildserver vm up. %s', e)
sys.exit(1)
-local_qt_filename = os.path.join(cachedir, 'qt-opensource-linux-x64-android-5.7.0.run')
-print("Setting executable bit for " + local_qt_filename)
-os.chmod(local_qt_filename, 0o755)
-
-# use VirtualBox software virtualization if hardware is not available,
-# like if this is being run in kvm or some other VM platform, like
-# http://jenkins.debian.net, the values are 'on' or 'off'
-if sys.platform.startswith('darwin'):
- # all < 10 year old Macs work, and OSX servers as VM host are very
- # rare, but this could also be auto-detected if someone codes it
- config['hwvirtex'] = 'on'
-elif os.path.exists('/proc/cpuinfo'):
- with open('/proc/cpuinfo') as f:
- contents = f.read()
- if 'vmx' in contents or 'svm' in contents:
- config['hwvirtex'] = 'on'
+ if config['copy_caches_from_host']:
+ ssh_config = v.ssh_config()
+ user = re.search(r'User ([^ \n]+)', ssh_config).group(1)
+ hostname = re.search(r'HostName ([^ \n]+)', ssh_config).group(1)
+ port = re.search(r'Port ([0-9]+)', ssh_config).group(1)
+ key = re.search(r'IdentityFile ([^ \n]+)', ssh_config).group(1)
+
+ for d in ('.m2', '.gradle/caches', '.gradle/wrapper', '.pip_download_cache'):
+ fullpath = os.path.join(os.getenv('HOME'), d)
+ if os.path.isdir(fullpath):
+ # TODO newer versions of vagrant provide `vagrant rsync`
+ run_via_vagrant_ssh(v, ['cd ~ && test -d', d, '|| mkdir -p', d])
+ subprocess.call(['rsync', '-axv', '--progress', '--delete', '-e',
+ 'ssh -i {0} -p {1} -oIdentitiesOnly=yes'.format(key, port),
+ fullpath + '/',
+ user + '@' + hostname + ':~/' + d + '/'])
+
+ # this file changes every time but should not be cached
+ run_via_vagrant_ssh(v, ['rm', '-f', '~/.gradle/caches/modules-2/modules-2.lock'])
+ run_via_vagrant_ssh(v, ['rm', '-fr', '~/.gradle/caches/*/plugin-resolution/'])
+
+ p = subprocess.Popen(['git', 'rev-parse', 'HEAD'], stdout=subprocess.PIPE,
+ universal_newlines=True)
+ buildserverid = p.communicate()[0].strip()
+ logger.info("Writing buildserver ID ...ID is %s", buildserverid)
+ run_via_vagrant_ssh(v, 'sh -c "echo %s >/home/vagrant/buildserverid"' % buildserverid)
-# Check against the existing Vagrantfile.yaml, and if they differ, we
-# need to create a new box:
-vf = os.path.join(serverdir, 'Vagrantfile.yaml')
-writevf = True
-if os.path.exists(vf):
- print('Halting', serverdir)
- vagrant(['halt'], serverdir)
- with open(vf, 'r', encoding='utf-8') as f:
- oldconfig = yaml.load(f)
- if config != oldconfig:
- print("Server configuration has changed, rebuild from scratch is required")
- vagrant(['destroy', '-f'], serverdir)
- else:
- print("Re-provisioning existing server")
- writevf = False
-else:
- print("No existing server - building from scratch")
-if writevf:
- with open(vf, 'w', encoding='utf-8') as f:
- yaml.dump(config, f)
+ logger.info("Stopping build server VM")
+ v.halt()
-if config['vm_provider'] == 'libvirt':
- returncode, out = vagrant(['box', 'list'], serverdir, printout=options.verbose)
- found_basebox = False
- needs_mutate = False
- for line in out.splitlines():
- if line.startswith(config['basebox']):
- found_basebox = True
- if line.split('(')[1].split(',')[0] != 'libvirt':
- needs_mutate = True
- continue
- if not found_basebox:
- if isinstance(config['baseboxurl'], str):
- baseboxurl = config['baseboxurl']
- else:
- baseboxurl = config['baseboxurl'][0]
- print('Adding', config['basebox'], 'from', baseboxurl)
- vagrant(['box', 'add', '--name', config['basebox'], baseboxurl],
- serverdir, printout=options.verbose)
- needs_mutate = True
- if needs_mutate:
- print('Converting', config['basebox'], 'to libvirt format')
- vagrant(['mutate', config['basebox'], 'libvirt'],
- serverdir, printout=options.verbose)
- print('Removing virtualbox format copy of', config['basebox'])
- vagrant(['box', 'remove', '--provider', 'virtualbox', config['basebox']],
- serverdir, printout=options.verbose)
-
-print("Configuring build server VM")
-returncode, out = vagrant(['up', '--provision'], serverdir, printout=True)
-with open(os.path.join(serverdir, 'up.log'), 'w') as log:
- log.write(out)
-if returncode != 0:
- print("Failed to configure server")
- sys.exit(1)
+ logger.info("Packaging")
+ boxfile = os.path.join(os.getcwd(), 'buildserver.box')
+ if os.path.exists(boxfile):
+ os.remove(boxfile)
+
+ vm.package(output=boxfile)
+
+ logger.info("Adding box")
+ vm.box_add('buildserver', boxfile, force=True)
-print("Writing buildserver ID")
-p = subprocess.Popen(['git', 'rev-parse', 'HEAD'], stdout=subprocess.PIPE,
- universal_newlines=True)
-buildserverid = p.communicate()[0].strip()
-print("...ID is " + buildserverid)
-subprocess.call(
- ['vagrant', 'ssh', '-c', 'sh -c "echo {0} >/home/vagrant/buildserverid"'
- .format(buildserverid)],
- cwd=serverdir)
-
-print("Stopping build server VM")
-vagrant(['halt'], serverdir)
-
-print("Waiting for build server VM to be finished")
-ready = False
-while not ready:
- time.sleep(2)
- returncode, out = vagrant(['status'], serverdir)
- if returncode != 0:
- print("Error while checking status")
+ if 'buildserver' not in subprocess.check_output(['vagrant', 'box', 'list']).decode('utf-8'):
+ logger.critical('could not add box \'%s\' as \'buildserver\', terminating', boxfile)
sys.exit(1)
- for line in out.splitlines():
- if line.startswith("default"):
- if line.find("poweroff") != -1:
- ready = True
- else:
- print("Status: " + line)
-print("Packaging")
-vagrant(['package', '--output', os.path.join('..', boxfile)], serverdir,
- printout=options.verbose)
-print("Adding box")
-vagrant(['box', 'add', 'buildserver', boxfile, '-f'],
- printout=options.verbose)
+ if not options.keep_box_file:
+ logger.debug('box added to vagrant, ' +
+ 'removing generated box file \'%s\'',
+ boxfile)
+ os.remove(boxfile)
+
-os.remove(boxfile)
+if __name__ == '__main__':
+ try:
+ main()
+ finally:
+ if tail is not None:
+ tail.stop()