diff options
author | Scott Lobdell <slobdell@google.com> | 2022-03-11 19:27:17 +0000 |
---|---|---|
committer | Scott Lobdell <slobdell@google.com> | 2022-03-11 19:57:09 +0000 |
commit | c9218ef1b82430a07d94f74c212a30e7ccc52975 (patch) | |
tree | 241b7fdeb6bdf1cf3af925ba8996f18faa8973d9 /floss/build/docker-build-image.py | |
parent | a26bda4d37221f2f7ef750b413502091e3bcddd4 (diff) | |
parent | 480d2270b269a0e47bf475eb439111f3f966e2a9 (diff) |
Merge TP1A.220225.003
Change-Id: Id71ac466dbfe3707fe2e544ce22b1da8f474ec2b
Diffstat (limited to 'floss/build/docker-build-image.py')
-rwxr-xr-x | floss/build/docker-build-image.py | 147 |
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() |