chiark / gitweb /
Merge branch 'master' into 'master'
[fdroidserver.git] / makebuildserver
index f745b0a3bb9861b5c8711cf353a08fed952ec9b8..6570e6796482b64c87550e66bbe1f289f1700df0 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 
 import os
 import sys
@@ -26,7 +26,7 @@ def vagrant(params, cwd=None, printout=False):
             line = p.stdout.readline()
             if len(line) == 0:
                 break
-            print line,
+            print(line)
             out += line
         p.wait()
     else:
@@ -41,29 +41,35 @@ parser.add_option("-v", "--verbose", action="store_true", default=False,
                   help="Spew out even more information than normal")
 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("--debian-mirror", default="http://http.debian.net/debian/",
-                  help="Use the specified Debian mirror in the box's /etc/apt/sources.list.")
 options, args = parser.parse_args()
 
 # set up default config
+cachedir = os.path.join(os.getenv('HOME'), '.cache', 'fdroidserver')
 config = {
     'arch64': False,
     'basebox': 'jessie32',
-    'baseboxurl': 'https://f-droid.org/jessie32.box',
-    'cachedir': os.path.join(os.getenv('HOME'), '.cache', 'fdroidserver'),
+    # TODO in py3, convert this to pathlib.Path(absolute_path_string).as_uri()
+    'baseboxurl': [
+        'file://' + os.path.join(cachedir, 'jessie32.box'),
+        'https://f-droid.org/jessie32.box',
+    ],
+    'debian_mirror': 'http://http.debian.net/debian/',
+    'apt_package_cache': False,
+    'boot_timeout': 600,
+    'cachedir': cachedir,
     'cpus': 1,
-    'memory': 3584,
+    'memory': 1024,
 }
 
 # load config file, if present
 if os.path.exists('makebuildserver.config.py'):
-    execfile('makebuildserver.config.py', config)
+    exec(compile(open('makebuildserver.config.py').read(), 'makebuildserver.config.py', 'exec'), config)
 elif os.path.exists('makebs.config.py'):
     # this is the old name for the config file
-    execfile('makebs.config.py', config)
+    exec(compile(open('makebs.config.py').read(), 'makebs.config.py', 'exec'), config)
 
 if not os.path.exists('makebuildserver') or not os.path.exists(serverdir):
-    print 'This must be run from the correct directory!'
+    print('This must be run from the correct directory!')
     sys.exit(1)
 
 if os.path.exists(boxfile):
@@ -75,7 +81,7 @@ if options.clean:
 # Update cached files.
 cachedir = config['cachedir']
 if not os.path.exists(cachedir):
-    os.makedirs(cachedir, 0755)
+    os.makedirs(cachedir, 0o755)
 
 cachefiles = [
     ('android-sdk_r24.4.1-linux.tgz',
@@ -263,6 +269,9 @@ cachefiles = [
     ('gradle-2.10-bin.zip',
      'https://services.gradle.org/distributions/gradle-2.10-bin.zip',
      '66406247f745fc6f05ab382d3f8d3e120c339f34ef54b86f6dc5f6efc18fbb13'),
+    ('gradle-2.11-bin.zip',
+     'https://services.gradle.org/distributions/gradle-2.11-bin.zip',
+     '8d7437082356c9fd6309a4479c8db307673965546daea445c6c72759cd6b1ed6'),
     ('Kivy-1.7.2.tar.gz',
      'https://pypi.python.org/packages/source/K/Kivy/Kivy-1.7.2.tar.gz',
      '0485e2ef97b5086df886eb01f8303cb542183d2d71a159466f99ad6c8a1d03f1'),
@@ -305,18 +314,21 @@ def sha256_for_file(path):
 
 for f, src, shasum in cachefiles:
     relpath = os.path.join(cachedir, f)
+    # if download fails to connect, it'll make a zero size file
+    if os.path.exists(relpath) and os.stat(relpath).st_size == 0:
+        os.remove(relpath)
     if not os.path.exists(relpath):
-        print "Downloading " + f + " to cache"
+        print("Downloading " + f + " to cache")
         if subprocess.call(['wget', src, '-O', f], cwd=cachedir) != 0:
-            print "...download of " + f + " failed."
+            print("...download of " + f + " failed.")
             sys.exit(1)
     if shasum:
         v = sha256_for_file(relpath)
         if v != shasum:
-            print "Invalid shasum of '" + v + "' detected for " + f
+            print("Invalid shasum of '" + v + "' detected for " + f)
             sys.exit(1)
         else:
-            print "...shasum verified for " + f
+            print("...shasum verified for " + f)
 
     wanted.append(f)
 
@@ -326,6 +338,20 @@ if type(config['baseboxurl']) in (list, tuple) or config['baseboxurl'][0] in ('(
 else:
     baseboxurl = '"{0}"'.format(config['baseboxurl'])
 
+# 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'
+hwvirtex = '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
+    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:
+        hwvirtex = 'on'
+
 # Generate an appropriate Vagrantfile for the buildserver, based on our
 # settings...
 vagrantfile = """
@@ -344,18 +370,38 @@ Vagrant.configure("2") do |config|
   config.vm.provider "virtualbox" do |v|
     v.customize ["modifyvm", :id, "--memory", "{2}"]
     v.customize ["modifyvm", :id, "--cpus", "{3}"]
+    v.customize ["modifyvm", :id, "--hwvirtex", "{4}"]
   end
 
+  config.vm.boot_timeout = {5}
+
   config.vm.provision :shell, :path => "fixpaths.sh"
 """.format(config['basebox'],
            baseboxurl,
            config['memory'],
-           config.get('cpus', 1))
+           config.get('cpus', 1),
+           hwvirtex,
+           config['boot_timeout'])
 if 'aptproxy' in config and config['aptproxy']:
     vagrantfile += """
   config.vm.provision :shell, :inline => 'sudo echo "Acquire::http {{ Proxy \\"{0}\\"; }};" > /etc/apt/apt.conf.d/02proxy && sudo apt-get update'
 """.format(config['aptproxy'])
 
+# buildserver/ is shared to the VM's /vagrant by default so the old default
+# does not need a custom mount
+if cachedir != 'buildserver/cache':
+    vagrantfile += """
+  config.vm.synced_folder '{0}', '/vagrant/cache'
+""".format(cachedir)
+
+# cache .deb packages on the host via a mount trick
+if config['apt_package_cache']:
+    aptcachedir = cachedir + '/apt/archives'
+    vagrantfile += """
+  config.vm.synced_folder "{0}", "/var/cache/apt/archives",
+    owner: 'root', group: 'root', create: true
+""".format(aptcachedir)
+
 vagrantfile += """
   config.vm.provision :chef_solo do |chef|
     chef.cookbooks_path = "cookbooks"
@@ -365,6 +411,7 @@ vagrantfile += """
         :sdk_loc => "/home/vagrant/android-sdk",
         :ndk_loc => "/home/vagrant/android-ndk",
         :debian_mirror => "%s",
+        :ubuntu_trusty => "%s",
         :user => "vagrant"
       }
     }
@@ -375,7 +422,8 @@ vagrantfile += """
     chef.add_recipe "kivy"
   end
 end
-""" % (options.debian_mirror)
+""" % (config['debian_mirror'],
+       str('14.04' in os.uname()[3]).lower())
 
 # Check against the existing Vagrantfile, and if they differ, we need to
 # create a new box:
@@ -386,57 +434,57 @@ if os.path.exists(vf):
     with open(vf, 'r') as f:
         oldvf = f.read()
     if oldvf != vagrantfile:
-        print "Server configuration has changed, rebuild from scratch is required"
+        print("Server configuration has changed, rebuild from scratch is required")
         vagrant(['destroy', '-f'], serverdir)
     else:
-        print "Re-provisioning existing server"
+        print("Re-provisioning existing server")
         writevf = False
 else:
-    print "No existing server - building from scratch"
+    print("No existing server - building from scratch")
 if writevf:
     with open(vf, 'w') as f:
         f.write(vagrantfile)
 
 
-print "Configuring build server VM"
+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"
+    print("Failed to configure server")
     sys.exit(1)
 
-print "Writing buildserver ID"
+print("Writing buildserver ID")
 p = subprocess.Popen(['git', 'rev-parse', 'HEAD'], stdout=subprocess.PIPE)
 buildserverid = p.communicate()[0].strip()
-print "...ID is " + buildserverid
+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"
+print("Stopping build server VM")
 vagrant(['halt'], serverdir)
 
-print "Waiting for build server VM to be finished"
+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"
+        print("Error while checking status")
         sys.exit(1)
     for line in out.splitlines():
         if line.startswith("default"):
             if line.find("poweroff") != -1:
                 ready = True
             else:
-                print "Status: " + line
+                print("Status: " + line)
 
-print "Packaging"
+print("Packaging")
 vagrant(['package', '--output', os.path.join('..', boxfile)], serverdir,
         printout=options.verbose)
-print "Adding box"
+print("Adding box")
 vagrant(['box', 'add', 'buildserver', boxfile, '-f'],
         printout=options.verbose)