Until now we've been happily building all version × suite combinations but that's not possible anymore (armel was dropped). Generating an empty recipe is just a proof of concept, based on the idea the Python script contains the logic, and the Makefile doesn't/shouldn't know about those details.
170 lines
5.3 KiB
Python
Executable File
170 lines
5.3 KiB
Python
Executable File
#!/usr/bin/python3
|
||
|
||
import re
|
||
import sys
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
# pylint: disable=invalid-name
|
||
|
||
### Sanity/usage checks
|
||
|
||
if len(sys.argv) != 3:
|
||
print("E: need 2 arguments", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
version = sys.argv[1]
|
||
if version not in ["1", "2", "3", "4"]:
|
||
print("E: unsupported version %s" % version, file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
suite = sys.argv[2]
|
||
if suite not in ['bullseye', 'bookworm', 'trixie', 'forky']:
|
||
print("E: unsupported suite %s" % suite, file=sys.stderr)
|
||
sys.exit(1)
|
||
target_yaml = 'raspi_%s_%s.yaml' % (version, suite)
|
||
|
||
|
||
### Detect unsupported combinations
|
||
#
|
||
# Some version/suite combinations are no longer supported (e.g. the architecture
|
||
# got removed from the archive), in which case generate an empty file and let
|
||
# the Makefile pick it up from there.
|
||
if version == '1' and suite in ['forky']:
|
||
print(f'W: generating an empty recipe for unsupported combination ({version}×{suite})')
|
||
Path(target_yaml).write_text('')
|
||
sys.exit(0)
|
||
|
||
|
||
### Setting variables based on suite and version starts here
|
||
|
||
# Arch, kernel, DTB:
|
||
if version == '1':
|
||
arch = 'armel'
|
||
linux = 'linux-image-rpi'
|
||
dtb = '/usr/lib/linux-image-*-rpi/bcm*rpi-*.dtb'
|
||
elif version == '2':
|
||
arch = 'armhf'
|
||
linux = 'linux-image-armmp'
|
||
dtb = '/usr/lib/linux-image-*-armmp/bcm*rpi*.dtb'
|
||
elif version in ['3', '4']:
|
||
arch = 'arm64'
|
||
linux = 'linux-image-arm64'
|
||
dtb = '/usr/lib/linux-image-*-arm64/broadcom/bcm*rpi*.dtb'
|
||
|
||
# Bookworm introduced the 'non-free-firmware' component¹; before that,
|
||
# raspi-firmware was in 'non-free'
|
||
#
|
||
# ¹ https://www.debian.org/vote/2022/vote_003
|
||
if suite != 'bullseye':
|
||
firmware_component = 'non-free-firmware'
|
||
firmware_component_old = 'non-free'
|
||
else:
|
||
firmware_component = 'non-free'
|
||
firmware_component_old = ''
|
||
|
||
# wireless firmware:
|
||
if version != '2':
|
||
wireless_firmware = 'firmware-brcm80211'
|
||
else:
|
||
wireless_firmware = ''
|
||
|
||
# bluetooth firmware:
|
||
if version != '2':
|
||
bluetooth_firmware = 'bluez-firmware'
|
||
else:
|
||
bluetooth_firmware = ''
|
||
|
||
# Pi 4 on buster required some backports. Let's keep variables around, ready to
|
||
# be used whenever we need to pull specific things from backports.
|
||
backports_enable = False
|
||
backports_suite = '%s-backports' % suite
|
||
|
||
# Serial console:
|
||
if version in ['1', '2']:
|
||
serial = 'ttyAMA0,115200'
|
||
elif version in ['3', '4']:
|
||
serial = 'ttyS1,115200'
|
||
|
||
# CMA fixup:
|
||
extra_chroot_shell_cmds = []
|
||
if version == '4':
|
||
extra_chroot_shell_cmds = [
|
||
"sed -i 's/cma=64M //' /boot/firmware/cmdline.txt",
|
||
]
|
||
|
||
# Hostname:
|
||
hostname = 'rpi_%s' % version
|
||
|
||
# Nothing yet!
|
||
extra_root_shell_cmds = []
|
||
|
||
|
||
### The following prepares substitutions based on variables set earlier
|
||
|
||
# Enable backports with a reason, or add commented-out entry:
|
||
if backports_enable:
|
||
backports_stanza = """
|
||
%s
|
||
deb http://deb.debian.org/debian/ %s main %s
|
||
""" % (backports_enable, backports_suite, firmware_component)
|
||
else:
|
||
# ugh
|
||
backports_stanza = """
|
||
# Backports are _not_ enabled by default.
|
||
# Enable them by uncommenting the following line:
|
||
# deb http://deb.debian.org/debian %s main %s
|
||
""" % (backports_suite, firmware_component)
|
||
|
||
gitcommit = subprocess.getoutput("git show -s --pretty='format:%C(auto)%h (%s, %ad)' --date=short ")
|
||
buildtime = subprocess.getoutput("date --utc +'%Y-%m-%d %H:%M'")
|
||
|
||
### Write results:
|
||
|
||
def align_replace(text, pattern, replacement):
|
||
"""
|
||
This helper lets us keep the indentation of the matched pattern
|
||
with the upcoming replacement, across multiple lines. Naive
|
||
implementation, please make it more pythonic!
|
||
"""
|
||
lines = text.splitlines()
|
||
for i, line in enumerate(lines):
|
||
m = re.match(r'^(\s+)%s' % pattern, line)
|
||
if m:
|
||
indent = m.group(1)
|
||
del lines[i]
|
||
for r in replacement:
|
||
lines.insert(i, '%s%s' % (indent, r))
|
||
i = i + 1
|
||
break
|
||
return '\n'. join(lines) + '\n'
|
||
|
||
|
||
with open('raspi_master.yaml', 'r') as in_file:
|
||
with open(target_yaml, 'w') as out_file:
|
||
in_text = in_file.read()
|
||
out_text = in_text \
|
||
.replace('__RELEASE__', suite) \
|
||
.replace('__ARCH__', arch) \
|
||
.replace('__FIRMWARE_COMPONENT__', firmware_component) \
|
||
.replace('__FIRMWARE_COMPONENT_OLD__', firmware_component_old) \
|
||
.replace('__LINUX_IMAGE__', linux) \
|
||
.replace('__DTB__', dtb) \
|
||
.replace('__WIRELESS_FIRMWARE__', wireless_firmware) \
|
||
.replace('__BLUETOOTH_FIRMWARE__', bluetooth_firmware) \
|
||
.replace('__SERIAL_CONSOLE__', serial) \
|
||
.replace('__HOST__', hostname) \
|
||
.replace('__GITCOMMIT__', gitcommit) \
|
||
.replace('__BUILDTIME__', buildtime)
|
||
|
||
out_text = align_replace(out_text, '__EXTRA_ROOT_SHELL_CMDS__', extra_root_shell_cmds)
|
||
out_text = align_replace(out_text, '__EXTRA_CHROOT_SHELL_CMDS__', extra_chroot_shell_cmds)
|
||
out_text = align_replace(out_text, '__BACKPORTS__', backports_stanza.splitlines())
|
||
|
||
# Try not to keep lines where the placeholder was replaced
|
||
# with nothing at all (including on a "list item" line):
|
||
filtered = [x for x in out_text.splitlines()
|
||
if not re.match(r'^\s+$', x)
|
||
and not re.match(r'^\s+-\s*$', x)]
|
||
out_file.write('\n'.join(filtered) + "\n")
|