summaryrefslogtreecommitdiff
path: root/floss/build/docker-build-image.py
diff options
context:
space:
mode:
authorAbhishek Pandit-Subedi <abhishekpandit@google.com>2022-02-14 13:39:10 -0800
committerAbhishek Pandit-Subedi <abhishekpandit@google.com>2022-02-18 13:44:56 -0800
commit6e1b4e8eddf3c20582e765f8917b66d68b3731c3 (patch)
treee2d185b6ca844a9ffd5a234bf6906b3bbdfcd712 /floss/build/docker-build-image.py
parent7b1fc1bae4a75089cfc0f163c56e76147158bc68 (diff)
floss: Add docker image for build
Add instructions on how to build with docker and include the dockerfile used to generate the image used. Also include a python script that can be run to generate the docker image and build everything. * `sudo ./docker-build-image.py --tag floss:latest` will build the docker image from scratch * `sudo ./build-in-docker.py` will build Floss in the current repository. Tag: #floss Bug: 220203992 Test: ./floss/build/docker-build.py and ./build.py inside container Change-Id: I0888a4e00de2d1f561874d6a555fc847538a131c
Diffstat (limited to 'floss/build/docker-build-image.py')
-rwxr-xr-xfloss/build/docker-build-image.py147
1 files changed, 147 insertions, 0 deletions
diff --git a/floss/build/docker-build-image.py b/floss/build/docker-build-image.py
new file mode 100755
index 0000000000..81b622b87b
--- /dev/null
+++ b/floss/build/docker-build-image.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import sys
+import subprocess
+
+SRC_MOUNT = "/root/src"
+
+
+class DockerImageBuilder:
+ """Builds the docker image for Floss build environment."""
+
+ def __init__(self, workdir, rootdir, tag):
+ """ Constructor.
+
+ Args:
+ workdir: Working directory for this script. Dockerfile should exist here.
+ rootdir: Root directory for Bluetooth.
+ tag: Label in format |name:version|.
+ """
+ self.workdir = workdir
+ self.rootdir = rootdir
+ (self.name, self.version) = tag.split(':')
+ self.build_tag = '{}:{}'.format(self.name, 'buildtemp')
+ self.container_name = 'floss-buildtemp'
+ self.final_tag = tag
+ self.env = os.environ.copy()
+
+ # Mark dpkg builders for docker
+ self.env['LIBCHROME_DOCKER'] = '1'
+ self.env['MODP_DOCKER'] = '1'
+
+ def run_command(self, target, args, cwd=None, env=None, ignore_rc=False):
+ """ Run command and stream the output.
+ """
+ # Set some defaults
+ if not cwd:
+ cwd = self.workdir
+ if not env:
+ env = self.env
+
+ rc = 0
+ process = subprocess.Popen(args, cwd=cwd, env=env, stdout=subprocess.PIPE)
+ while True:
+ line = process.stdout.readline()
+ print(line.decode('utf-8'), end="")
+ if not line:
+ rc = process.poll()
+ if rc is not None:
+ break
+
+ time.sleep(0.1)
+
+ if rc != 0 and not ignore_rc:
+ raise Exception("{} failed. Return code is {}".format(target, rc))
+
+ def _docker_build(self):
+ self.run_command('docker build', ['docker', 'build', '-t', self.build_tag, '.'])
+
+ def _build_dpkg_and_commit(self):
+ # Try to remove any previous instance of the container that may be
+ # running if this script didn't complete cleanly last time.
+ self.run_command('docker stop', ['docker', 'stop', '-t', '1', self.container_name], ignore_rc=True)
+ self.run_command('docker rm', ['docker', 'rm', self.container_name], ignore_rc=True)
+
+ # Runs never terminating application on the newly built image in detached mode
+ mount_str = 'type=bind,src={},dst={},readonly'.format(self.rootdir, SRC_MOUNT)
+ self.run_command('docker run', [
+ 'docker', 'run', '--name', self.container_name, '--mount', mount_str, '-d', self.build_tag, 'tail', '-f',
+ '/dev/null'
+ ])
+
+ commands = [
+ # Create the output directories
+ ['mkdir', '-p', '/tmp/libchrome', '/tmp/modpb64'],
+
+ # Run the dpkg builder for modp_b64
+ ['/root/src/system/build/dpkg/modp_b64/gen-src-pkg.sh', '/tmp/modpb64'],
+
+ # Install modp_b64 since libchrome depends on it
+ ['find', '/tmp/modpb64', '-name', 'modp*.deb', '-exec', 'dpkg', '-i', '{}', '+'],
+
+ # Run the dpkg builder for libchrome
+ ['/root/src/system/build/dpkg/libchrome/gen-src-pkg.sh', '/tmp/libchrome'],
+
+ # Install libchrome.
+ ['find', '/tmp/libchrome', '-name', 'libchrome_*.deb', '-exec', 'dpkg', '-i', '{}', '+'],
+
+ # Delete intermediate files
+ ['rm', '-rf', '/tmp/libchrome', '/tmp/modpb64'],
+ ]
+
+ # Run commands in container first to install everything.
+ for i, cmd in enumerate(commands):
+ self.run_command('docker exec #{}'.format(i), ['docker', 'exec', '-it', self.container_name] + cmd)
+
+ # Commit changes into the final tag name
+ self.run_command('docker commit', ['docker', 'commit', self.container_name, self.final_tag])
+
+ # Stop running the container and remove it
+ self.run_command('docker stop', ['docker', 'stop', '-t', '1', self.container_name])
+ self.run_command('docker rm', ['docker', 'rm', self.container_name])
+
+ def _check_docker_runnable(self):
+ try:
+ subprocess.check_output(['docker', 'ps'], stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as err:
+ if 'denied' in err.output.decode('utf-8'):
+ print('Run script as sudo')
+ else:
+ print('Unexpected error: {}'.format(err.output.decode('utf-8')))
+
+ return False
+
+ # No exception means docker is ok
+ return True
+
+ def build(self):
+ if not self._check_docker_runnable():
+ return
+
+ # First build the docker image
+ self._docker_build()
+
+ # Then build libchrome and modp-b64 inside the docker image and install
+ # them. Commit those changes to the final label.
+ self._build_dpkg_and_commit()
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Build docker image for Floss build environment.')
+ parser.add_argument('--tag', required=True, help='Tag for docker image. i.e. floss:latest')
+ args = parser.parse_args()
+
+ # cwd should be set to same directory as this script (that's where Dockerfile
+ # is kept).
+ workdir = os.path.dirname(os.path.abspath(sys.argv[0]))
+ rootdir = os.path.abspath(os.path.join(workdir, '../..'))
+
+ # Build the docker image
+ dib = DockerImageBuilder(workdir, rootdir, args.tag)
+ dib.build()
+
+
+if __name__ == '__main__':
+ main()