1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
#!/usr/bin/env python3
import argparse
import os
import sys
import subprocess
SRC_MOUNT = "/root/src"
class PodmanImageBuilder:
"""Builds the podman 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 podman
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 _podman_build(self):
self.run_command('podman build', ['podman', '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('podman stop', ['podman', 'stop', '-t', '1', self.container_name], ignore_rc=True)
self.run_command('podman rm', ['podman', '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('podman run', [
'podman', '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
[f'{SRC_MOUNT}/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
[f'{SRC_MOUNT}/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'],
]
try:
# Run commands in container first to install everything.
for i, cmd in enumerate(commands):
self.run_command('podman exec #{}'.format(i), ['podman', 'exec', '-it', self.container_name] + cmd)
# Commit changes into the final tag name
self.run_command('podman commit', ['podman', 'commit', self.container_name, self.final_tag])
finally:
# Stop running the container and remove it
self.run_command('podman stop', ['podman', 'stop', '-t', '1', self.container_name])
self.run_command('podman rm', ['podman', 'rm', self.container_name])
def _check_podman_runnable(self):
try:
subprocess.check_output(['podman', '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 podman is ok
return True
def build(self):
if not self._check_podman_runnable():
return
# First build the podman image
self._podman_build()
# Then build libchrome and modp-b64 inside the podman image and install
# them. Commit those changes to the final label.
self._build_dpkg_and_commit()
def main():
parser = argparse.ArgumentParser(description='Build podman image for Floss build environment.')
parser.add_argument('--tag', required=True, help='Tag for podman 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 podman image
pib = PodmanImageBuilder(workdir, rootdir, args.tag)
pib.build()
if __name__ == '__main__':
main()
|