Initial work on using docker for Linux builds. docker
authorCarl Hetherington <cth@carlh.net>
Wed, 5 Jul 2017 11:02:48 +0000 (12:02 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 5 Jul 2017 11:02:48 +0000 (12:02 +0100)
cdist

diff --git a/cdist b/cdist
index ecb71d531e59a5d2ad5a5fc1e1a29b9117608825..22d2d0376067ffd47c7357ddb1461431b34e7731 100755 (executable)
--- a/cdist
+++ b/cdist
@@ -28,6 +28,7 @@ import subprocess
 import re
 import copy
 import inspect
+import shlex
 
 TEMPORARY_DIRECTORY = '/var/tmp'
 
@@ -92,8 +93,7 @@ class BoolOption(object):
 
 class Config:
     def __init__(self):
-        self.options = [ Option('linux_chroot_prefix'),
-                         Option('windows_environment_prefix'),
+        self.options = [ Option('windows_environment_prefix'),
                          Option('mingw_prefix'),
                          Option('git_prefix'),
                          Option('osx_build_host'),
@@ -184,7 +184,7 @@ def command(c):
 
 def command_and_read(c):
     log(c)
-    p = subprocess.Popen(c.split(), stdout=subprocess.PIPE)
+    p = subprocess.Popen(shlex.split(c), stdout=subprocess.PIPE)
     f = os.fdopen(os.dup(p.stdout.fileno()))
     return f
 
@@ -253,10 +253,10 @@ class TreeDirectory:
     def __init__(self, tree):
         self.tree = tree
     def __enter__(self):
-        self.cwd = os.getcwd()
-        os.chdir('%s/src/%s' % (self.tree.target.directory, self.tree.name))
+        self.cwd = self.tree.target.getcwd()
+        self.tree.target.chdir('%s/src/%s' % (self.tree.target.directory, self.tree.name))
     def __exit__(self, type, value, traceback):
-        os.chdir(self.cwd)
+        self.tree.target.chdir(self.cwd)
 
 #
 # Version
@@ -390,6 +390,11 @@ class Target(object):
         if self.rmdir:
             rmtree(self.directory)
 
+    def chdir(self, dir):
+        os.chdir(dir)
+
+    def getcwd(self):
+        return os.getcwd()
 
 class WindowsTarget(Target):
     """
@@ -465,20 +470,29 @@ class LinuxTarget(Target):
                  '%s/lib/pkgconfig:%s/lib64/pkgconfig:/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig' % (self.directory, self.directory))
         self.set('PATH', '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin')
 
-class ChrootTarget(LinuxTarget):
-    """Build in a chroot"""
-    def __init__(self, distro, version, bits, directory=None):
-        super(ChrootTarget, self).__init__(distro, version, bits, directory)
-        # e.g. ubuntu-14.04-64
+class DockerTarget(LinuxTarget):
+    """Build in a Docker container"""
+    def __init__(self, distro, version, bits):
+        super(DockerTarget, self).__init__(distro, version, bits, "/cdist")
         if self.version is not None and self.bits is not None:
-            self.chroot = '%s-%s-%d' % (self.distro, self.version, self.bits)
+            image = '%s-%s' % (self.distro, self.version)
         else:
-            self.chroot = self.distro
-        # e.g. /home/carl/Environments/ubuntu-14.04-64
-        self.chroot_prefix = '%s/%s' % (config.get('linux_chroot_prefix'), self.chroot)
+            image = self.distro
+        self.container = command_and_read('docker run -itd %s' % image).read().strip()[:12]
+        self.dir = '/'
+        self.command('mkdir -p %s/src' % self.directory)
 
     def command(self, c):
-        command('%s schroot -c %s -p -- %s' % (self.variables_string(), self.chroot, c))
+        command('docker exec -t %s /bin/bash -c "cd %s && %s %s"' % (self.container, self.dir, self.variables_string(True), c))
+
+    def command_and_read(self, c):
+        return command_and_read('docker exec -t %s /bin/bash -c "cd %s && %s %s"' % (self.container, self.dir, self.variables_string(True), c))
+
+    def chdir(self, dir):
+        self.dir = dir
+
+    def getcwd(self):
+        return self.dir
 
 
 class HostTarget(LinuxTarget):
@@ -489,28 +503,6 @@ class HostTarget(LinuxTarget):
     def command(self, c):
         command('%s %s' % (self.variables_string(), c))
 
-
-class DockerTarget(Target):
-    """
-    Build a Docker image.
-
-    This target exposes the following additional API:
-
-    deb: path to Debian 8 .deb
-    """
-    def __init__(self, directory=None):
-        super(DockerTarget, self).__init__('docker', directory)
-        self.debian = ChrootTarget('debian', '8', 64, directory)
-
-    def command(self, c):
-        log('host -> %s' % c)
-        command('%s %s' % (self.variables_string(), c))
-
-    def package(self, project, checkout):
-        self.deb = self.debian.package(project, checkout)
-        return globals.trees.get(project, checkout, self).call('package', tree.version), tree.git_commit
-
-
 class OSXTarget(Target):
     def __init__(self, directory=None):
         super(OSXTarget, self).__init__('osx', directory)
@@ -607,7 +599,7 @@ def target_factory(s, debug, work):
         p = s.split('-')
         if len(p) != 3:
             raise Error("Bad Linux target name `%s'; must be something like ubuntu-12.04-32 (i.e. distro-version-bits)" % s)
-        target = ChrootTarget(p[0], p[1], int(p[2]), work)
+        target = DockerTarget(p[0], p[1], int(p[2]))
     elif s.startswith('arch-'):
         p = s.split('-')
         if len(p) != 2:
@@ -638,8 +630,6 @@ def target_factory(s, debug, work):
             target = OSXUniversalTarget(work)
     elif s == 'source':
         target = SourceTarget()
-    elif s == 'docker':
-        target = DockerTarget()
 
     if target is None:
         raise Error("Bad target `%s'" % s)
@@ -672,42 +662,42 @@ class Tree(object):
         self.git_commit = None
         self.built = False
 
-        cwd = os.getcwd()
+        cwd = self.target.getcwd()
 
         flags = ''
         redirect = ''
         if globals.quiet:
             flags = '-q'
             redirect = '>/dev/null'
-        command('git clone %s %s/%s.git %s/src/%s' % (flags, config.get('git_prefix'), self.name, target.directory, self.name))
-        os.chdir('%s/src/%s' % (target.directory, self.name))
+        self.target.command('git clone %s %s/%s.git %s/src/%s' % (flags, config.get('git_prefix'), self.name, target.directory, self.name))
+        self.target.chdir('%s/src/%s' % (target.directory, self.name))
 
         spec = self.specifier
         if spec is None:
             spec = 'master'
 
-        command('git checkout %s %s %s' % (flags, spec, redirect))
+        self.target.command('git checkout %s %s %s' % (flags, spec, redirect))
         self.git_commit = command_and_read('git rev-parse --short=7 HEAD').readline().strip()
-        command('git submodule init --quiet')
-        command('git submodule update --quiet')
+        self.target.command('git submodule init --quiet')
+        self.target.command('git submodule update --quiet')
 
         proj = '%s/src/%s' % (target.directory, self.name)
 
         self.cscript = {}
-        exec(open('%s/cscript' % proj).read(), self.cscript)
+        exec(self.target.command_and_read('cat %s/cscript' % proj).read(), self.cscript)
 
         if os.path.exists('%s/wscript' % proj):
             v = read_wscript_variable(proj, "VERSION");
             if v is not None:
                 self.version = Version(v)
 
-        os.chdir(cwd)
+        self.target.chdir(cwd)
 
     def call(self, function, *args):
         with TreeDirectory(self):
             return self.cscript[function](self.target, *args)
 
-    def build_dependencies(self, options=None):
+    def build_dependencies(self, options=dict()):
 
         if not 'dependencies' in self.cscript:
             return
@@ -740,7 +730,7 @@ class Tree(object):
             dep.build_dependencies(options)
             dep.build(options)
 
-    def build(self, options=None):
+    def build(self, options=dict()):
         if self.built:
             return