Skip to content

Commit e6bb228

Browse files
authored
Merge pull request #105 from nathanchance/move-images-to-releases
Move images to GitHub releases
2 parents 012c3ac + 98f47f1 commit e6bb228

23 files changed

+322
-137
lines changed

.github/workflows/main.yml

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Run shellcheck and shfmt on all shell files and several Python linters on all Python files in this repository
1+
# Run several Python linters on all Python files in this repository
22
name: Lint checks
33
on: [push, pull_request]
44
jobs:
@@ -10,7 +10,3 @@ jobs:
1010
uses: ClangBuiltLinux/actions-workflows/.github/workflows/python_lint.yml@main
1111
with:
1212
python_version: ${{ matrix.version }}
13-
shellcheck:
14-
uses: ClangBuiltLinux/actions-workflows/.github/workflows/shellcheck.yml@main
15-
shfmt:
16-
uses: ClangBuiltLinux/actions-workflows/.github/workflows/shfmt.yml@main

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
images/
12
qemu-binaries/
23
*.pyc

boot-qemu.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import utils
1616

17-
BOOT_UTILS = Path(__file__).resolve().parent
1817
SUPPORTED_ARCHES = [
1918
'arm',
2019
'arm32_v5',
@@ -45,6 +44,7 @@ def __init__(self):
4544
self.efi = False
4645
self.gdb = False
4746
self.gdb_bin = ''
47+
self.gh_json_file = None
4848
self.interactive = False
4949
self.kernel = None
5050
self.kernel_dir = None
@@ -163,16 +163,8 @@ def _have_dev_kvm_access(self):
163163
def _prepare_initrd(self):
164164
if not self._initrd_arch:
165165
raise RuntimeError('No initrd architecture specified?')
166-
if not (src := Path(BOOT_UTILS, 'images', self._initrd_arch,
167-
'rootfs.cpio.zst')):
168-
raise FileNotFoundError(f"initrd ('{src}') does not exist?")
169-
170-
(dst := src.with_suffix('')).unlink(missing_ok=True)
171-
172-
utils.check_cmd('zstd')
173-
subprocess.run(['zstd', '-d', src, '-o', dst, '-q'], check=True)
174-
175-
return dst
166+
return utils.prepare_initrd(self._initrd_arch,
167+
gh_json_file=self.gh_json_file)
176168

177169
def _run_fg(self):
178170
# Pretty print and run QEMU command
@@ -370,7 +362,7 @@ def _can_use_kvm(self):
370362
# 32-bit EL1 is not supported on all cores so support for it must be
371363
# explicitly queried via the KVM_CHECK_EXTENSION ioctl().
372364
try:
373-
subprocess.run(Path(BOOT_UTILS, 'utils',
365+
subprocess.run(Path(utils.BOOT_UTILS, 'utils',
374366
'aarch64_32_bit_el1_supported'),
375367
check=True)
376368
except subprocess.CalledProcessError:
@@ -437,7 +429,7 @@ def _setup_efi(self):
437429
]
438430
aavmf = utils.find_first_file(usr_share, aavmf_locations)
439431

440-
self._efi_img = Path(BOOT_UTILS, 'images', self._initrd_arch,
432+
self._efi_img = Path(utils.BOOT_UTILS, 'images', self._initrd_arch,
441433
'efi.img')
442434
# This file is in /usr/share, so it must be copied in order to be
443435
# modified.
@@ -652,7 +644,7 @@ def run(self):
652644
Path('OVMF/OVMF_VARS.fd'), # Debian and Ubuntu
653645
]
654646
ovmf_vars = utils.find_first_file(usr_share, ovmf_vars_locations)
655-
self._efi_vars = Path(BOOT_UTILS, 'images', self.initrd_arch,
647+
self._efi_vars = Path(utils.BOOT_UTILS, 'images', self.initrd_arch,
656648
ovmf_vars.name)
657649
# This file is in /usr/share, so it must be copied in order to be
658650
# modified.
@@ -750,6 +742,11 @@ def parse_arguments():
750742
'--gdb-bin',
751743
default='gdb-multiarch',
752744
help='gdb binary to use for debugging (default: gdb-multiarch)')
745+
parser.add_argument(
746+
'--gh-json-file',
747+
help=
748+
'Use file for downloading rootfs images, instead of querying GitHub API directly'
749+
)
753750
parser.add_argument(
754751
'-k',
755752
'--kernel-location',
@@ -837,6 +834,9 @@ def parse_arguments():
837834
runner.gdb = True
838835
runner.gdb_bin = args.gdb_bin
839836

837+
if args.gh_json_file:
838+
runner.gh_json_file = Path(args.gh_json_file).resolve()
839+
840840
if args.no_kvm:
841841
runner.use_kvm = False
842842

boot-uml.py

+13-23
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
import utils
99

10-
base_folder = Path(__file__).resolve().parent
11-
1210

1311
def parse_arguments():
1412
"""
@@ -19,6 +17,12 @@ def parse_arguments():
1917
"""
2018
parser = argparse.ArgumentParser()
2119

20+
parser.add_argument(
21+
'-g',
22+
'--gh-json-file',
23+
help=
24+
'Use file for downloading rootfs images, instead of querying GitHub API directly'
25+
)
2226
parser.add_argument(
2327
"-i",
2428
"--interactive",
@@ -38,26 +42,6 @@ def parse_arguments():
3842
return parser.parse_args()
3943

4044

41-
def decomp_rootfs():
42-
"""
43-
Decompress and get the full path of the initial ramdisk for use with UML.
44-
45-
Returns:
46-
rootfs (Path): rootfs Path object containing full path to rootfs.
47-
"""
48-
rootfs = base_folder.joinpath("images", "x86_64", "rootfs.ext4")
49-
50-
# This could be 'rootfs.unlink(missing_ok=True)' but that was only added in Python 3.8.
51-
if rootfs.exists():
52-
rootfs.unlink()
53-
54-
utils.check_cmd("zstd")
55-
subprocess.run(["zstd", "-q", "-d", f"{rootfs}.zst", "-o", rootfs],
56-
check=True)
57-
58-
return rootfs
59-
60-
6145
def run_kernel(kernel_image, rootfs, interactive):
6246
"""
6347
Run UML command with path to rootfs and additional arguments based on user
@@ -77,6 +61,12 @@ def run_kernel(kernel_image, rootfs, interactive):
7761

7862
if __name__ == '__main__':
7963
args = parse_arguments()
64+
8065
kernel = utils.get_full_kernel_path(args.kernel_location, "linux")
8166

82-
run_kernel(kernel, decomp_rootfs(), args.interactive)
67+
initrd_args = {'rootfs_format': 'ext4'}
68+
if args.gh_json_file:
69+
initrd_args['gh_json_file'] = Path(args.gh_json_file).resolve()
70+
initrd = utils.prepare_initrd('x86_64', **initrd_args)
71+
72+
run_kernel(kernel, initrd, args.interactive)

buildroot/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
src/
2+
out/

buildroot/rebuild.py

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#!/usr/bin/env python3
2+
3+
from argparse import ArgumentParser
4+
import datetime
5+
import os
6+
from pathlib import Path
7+
import shutil
8+
import subprocess
9+
10+
BUILDROOT_VERSION = '2022.02'
11+
SUPPORTED_ARCHES = [
12+
'arm64',
13+
'arm64be',
14+
'arm',
15+
'm68k',
16+
'mips',
17+
'mipsel',
18+
'ppc32',
19+
'ppc64',
20+
'ppc64le',
21+
'riscv',
22+
's390',
23+
'x86',
24+
'x86_64',
25+
]
26+
RELEASE_TAG = datetime.datetime.now(
27+
tz=datetime.timezone.utc).strftime('%Y%m%d-%H%M%S')
28+
ROOT_FOLDER = Path(__file__).resolve().parent
29+
OUT_FOLDER = Path(ROOT_FOLDER, 'out')
30+
SRC_FOLDER = Path(ROOT_FOLDER, 'src')
31+
32+
33+
def buildroot_make(make_arg=None, **kwargs):
34+
make_cmd = ['make', f"-j{os.cpu_count()}"]
35+
if make_arg:
36+
make_cmd.append(make_arg)
37+
subprocess.run(make_cmd, **kwargs, check=True, cwd=SRC_FOLDER)
38+
39+
40+
def build_image(architecture, edit_config):
41+
buildroot_make('clean')
42+
43+
config = Path(ROOT_FOLDER, f"{architecture}.config")
44+
# Python documentation notes that when subprocess.Popen()'s env parameter
45+
# is not None, the current process's envirionment is not inherited, which
46+
# causes issues because PATH is not inherited. Add BR2_DEFCONFIG to the
47+
# environment, rather than replacing it (we support Python 3.8, so we
48+
# cannot use 'os.environ | {...}').
49+
buildroot_make('defconfig', env={**os.environ, 'BR2_DEFCONFIG': config})
50+
if edit_config:
51+
buildroot_make('menuconfig')
52+
buildroot_make('savedefconfig')
53+
54+
buildroot_make()
55+
56+
OUT_FOLDER.mkdir(exist_ok=True, parents=True)
57+
58+
images = [Path(SRC_FOLDER, 'output/images/rootfs.cpio')]
59+
# For x86_64, we also build an ext4 image for UML
60+
if architecture == 'x86_64':
61+
images.append(images[0].with_suffix('.ext4'))
62+
63+
for image in images:
64+
if not image.exists():
65+
raise FileNotFoundError(
66+
f"{image} could not be found! Did the build error?")
67+
zstd_cmd = [
68+
'zstd', '-f', '-19', '-o',
69+
Path(OUT_FOLDER, f"{architecture}-{image.name}.zst"), image
70+
]
71+
subprocess.run(zstd_cmd, check=True)
72+
73+
74+
def download_and_extract_buildroot():
75+
SRC_FOLDER.mkdir(parents=True)
76+
77+
tarball = Path(ROOT_FOLDER, f"buildroot-{BUILDROOT_VERSION}.tar.gz")
78+
tarball.unlink(missing_ok=True)
79+
80+
curl_cmd = [
81+
'curl', '-LSs', '-o', tarball,
82+
f"https://buildroot.org/downloads/{tarball.name}"
83+
]
84+
subprocess.run(curl_cmd, check=True)
85+
86+
sha256_cmd = ['sha256sum', '--quiet', '-c', f"{tarball.name}.sha256"]
87+
subprocess.run(sha256_cmd, check=True, cwd=ROOT_FOLDER)
88+
89+
tar_cmd = [
90+
'tar', '-C', SRC_FOLDER, '--strip-components=1', '-axf', tarball
91+
]
92+
subprocess.run(tar_cmd, check=True)
93+
94+
tarball.unlink(missing_ok=True)
95+
96+
97+
def download_buildroot_if_necessary():
98+
if SRC_FOLDER.exists():
99+
# Make support/scripts/setlocalversion do nothing because we are in a
100+
# git repository so it will return information about this repo, not
101+
# Buildroot
102+
setlocalversion = Path(SRC_FOLDER, 'support/scripts/setlocalversion')
103+
setlocalversion.write_text('', encoding='utf-8')
104+
105+
installed_version = subprocess.run(['make', 'print-version'],
106+
capture_output=True,
107+
check=True,
108+
cwd=SRC_FOLDER,
109+
text=True).stdout.strip()
110+
if installed_version != BUILDROOT_VERSION:
111+
shutil.rmtree(SRC_FOLDER)
112+
download_and_extract_buildroot()
113+
else:
114+
download_and_extract_buildroot()
115+
116+
117+
def release_images():
118+
if not shutil.which('gh'):
119+
raise RuntimeError(
120+
"Could not find GitHub CLI ('gh') on your system, please install it to do releases!"
121+
)
122+
123+
gh_cmd = [
124+
'gh', '-R', 'ClangBuiltLinux/boot-utils', 'release', 'create',
125+
'--generate-notes', RELEASE_TAG, *list(OUT_FOLDER.iterdir())
126+
]
127+
subprocess.run(gh_cmd, check=True)
128+
129+
130+
def parse_arguments():
131+
parser = ArgumentParser()
132+
133+
parser.add_argument(
134+
'-a',
135+
'--architectures',
136+
choices=[*SUPPORTED_ARCHES, 'all'],
137+
default=SUPPORTED_ARCHES,
138+
help=
139+
'The architectures to build images for. Defaults to all supported architectures.',
140+
nargs='+')
141+
parser.add_argument(
142+
'-e',
143+
'--edit-config',
144+
action='store_true',
145+
help='Edit configuration file and run savedefconfig on result')
146+
parser.add_argument(
147+
'-r',
148+
'--release',
149+
action='store_true',
150+
help=f"Create a release on GitHub (tag: {RELEASE_TAG})")
151+
152+
return parser.parse_args()
153+
154+
155+
if __name__ == '__main__':
156+
args = parse_arguments()
157+
158+
if not shutil.which('zstd'):
159+
raise RuntimeError(
160+
'zstd could not be found on your system, please install it!')
161+
162+
architectures = SUPPORTED_ARCHES if 'all' in args.architectures else args.architectures
163+
164+
download_buildroot_if_necessary()
165+
for arch in architectures:
166+
build_image(arch, args.edit_config)
167+
168+
if args.release:
169+
release_images()

0 commit comments

Comments
 (0)