new file mode 100755
@@ -0,0 +1,8 @@
+#! /usr/bin/make -f
+
+clean:
+ ./debian/scripts/gen-rules
+ $(MAKE) -f debian/rules.gen clean
+
+%:
+ $(MAKE) -f debian/rules.gen $@
new file mode 100755
@@ -0,0 +1,109 @@
+#!/usr/bin/python3
+
+import os
+import sys
+import json
+from textwrap import dedent, indent
+
+
+def dedent_makefile(raw, prefix=''):
+ lines = []
+ for line in indent(dedent(raw), prefix=prefix).rstrip().split("\n"):
+ lines.append(line.replace(" ", " ", 1))
+ return "\n".join(lines)
+
+with open("debian/changelog") as cfd:
+ bits = cfd.readline().split()
+ source_name = bits[0]
+
+with open("debian/files.json") as ffd:
+ signing_config = json.load(ffd)
+
+if source_name not in signing_config:
+ raise ValueError(f"{source_name} not found in files.json")
+
+to_sign = signing_config[source_name]
+
+overall_archs = set()
+for file in to_sign["files"]:
+ overall_archs.add(file["arch"])
+
+# Convert debian/control: pull off and rename the source stanza. Also add a
+# simple build interlock package as we have to produce something.
+in_control = os.path.join("debian", "control.common")
+out_control = os.path.join("debian", "control")
+with open(in_control) as ifd, open(out_control, "w") as ofd:
+ for line in ifd:
+ print(line, end='', file=ofd)
+
+ print(dedent(f"""\
+
+ Package: {source_name}
+ Architecture: {" ".join(sorted(overall_archs))}
+ Section: kernel
+ Description: Build interlock package
+ Build interlock package. You do not want to install this package.
+ """.rstrip()), file=ofd)
+
+out_rules = os.path.join("debian", "rules.gen")
+with open(out_rules, "w") as ofd:
+ print(dedent_makefile("""\
+ #! /usr/bin/make -f
+ arch = $(shell dpkg-architecture -qDEB_HOST_ARCH)
+ source = $(shell dpkg-parsechangelog -SSource)
+ version = $(shell dpkg-parsechangelog -SVersion)
+
+ clean::
+ dh_clean
+ rm -rf $(custom_top)
+
+ %:
+ dh $@
+
+ define copy_or_download =
+ if [ -r "$(1)" ]; then \\
+ exec cp -p "$(1)" "$(2)"; \\
+ fi; \\
+ pkg=$$(dpkg -S "$(1)" | awk -F: '{print $$1;}'); \\
+ apt-get download $${pkg} || exit 1; \\
+ for deb in $${pkg}_*.deb; do break; done; \\
+ dpkg-deb -x "$$deb" "$$deb--contents" || exit 1; \\
+ cp -p "$$deb--contents$(1)" "$(2)"; \\
+ rm -rf "$$deb--contents"
+ endef
+
+ custom_top=debian/custom
+ custom_dir=$(custom_top)/$(version)
+ custom_tar=$(source)_$(version)_$(arch).tar.gz
+ custom-upload:
+ install -d $(custom_dir)/control
+ { echo "tarball"; } >$(custom_dir)/control/options
+ cd $(custom_top) && tar czvf ../../../$(custom_tar) .
+ dpkg-distaddfile $(custom_tar) raw-signing -
+
+ override_dh_auto_install: generate-$(arch) custom-upload
+ dh_install
+ """), file=ofd)
+
+ for signing in to_sign["files"]:
+ arch = signing["arch"]
+ in_file = signing["file"]
+ out_file = signing["file"]
+ out_file = "$(custom_dir)" + signing["file"] + "." + signing["sig_type"]
+ print(dedent_makefile(f'''\
+
+ generate-{arch}::
+ install -d {os.path.dirname(out_file)}
+ $(call copy_or_download,{in_file},{out_file})
+ '''), file=ofd)
+ # arm64 platforms normally have compressed gzip'd kernels, these must be
+ # uncompressed for sigining and recompressed later. Where indicated gunzip
+ # the file and mark it for recompression in -signed.
+ if signing["sig_type"] == "efi" and arch == "arm64":
+ print(dedent_makefile(f'''\
+ gunzip -cv <{out_file} >{out_file}.gunzip; \\
+ mv -f {out_file}.gunzip {out_file}; \\
+ echo "GZIP=1" >>{out_file}.vars; \\
+ ''', prefix=' '), file=ofd)
+
+os.chmod(out_rules, 0o755)
@@ -24,6 +24,7 @@ src_headers_arch = linux-headers-$(abi)-generic
pre-clean:
rm -f debian/control
./debian/scripts/generate-control $(series) $(src) $(ver) $(unsigned_src) $(unsigned_ver) $(abi)
+ ./debian/scripts/parameterise-ancillaries $(abi) $(generate_src)
rm -rf ./$(unsigned_ver) UNSIGNED SIGNED
rm -f debian/linux-image-*.install \
debian/linux-image-*.preinst \
@@ -6,7 +6,7 @@ from textwrap import dedent
from config import Signing
-(series, source_name, source_version, unsigned_name, unsigned_version, abi_version) = sys.argv[1:]
+(series, source_name, generate_name, source_version, unsigned_name, unsigned_version, abi_version) = sys.argv[1:]
signing = Signing.load("debian/package.config")
@@ -17,6 +17,7 @@ with open("debian/control.stub") as tfd, open("debian/control", "w") as cfd:
if "@DEPENDS@" in line:
for flavour, archs in signing.flavour_archs:
print(f' linux-image-unsigned-{abi_version}-{flavour} [{" ".join(archs)}],', file=cfd)
+ print(f" {generate_name} (= {source_version}),", file=cfd)
else:
print(line, end='', file=cfd)
new file mode 100755
@@ -0,0 +1,78 @@
+#!/usr/bin/python3 -B
+
+import os
+import sys
+import json
+from shutil import copy
+from textwrap import dedent, indent
+
+from config import Signing
+
+
+def build_changelog(outd, source_name):
+ # Convert debian/changelog: fix the package name in the first stanza.
+ in_changelog = os.path.join("debian", "changelog")
+ out_changelog = os.path.join(outd, "debian", "changelog")
+ with open(in_changelog) as ifd, open(out_changelog, "w") as ofd:
+ first = True
+ stanza = 0
+ for line in ifd:
+ if line[0] not in (" ", "\n"):
+ stanza += 1
+ first = True
+ if stanza == 3:
+ break
+ if first:
+ bits = line.split()
+ bits[0] = source_name
+ print(" ".join(bits), file=ofd)
+ first = False
+ else:
+ print(line, end="", file=ofd)
+
+# Build one of the ancillaries.
+def build_ancillary(package):
+ outd = os.path.join("debian", "ancillary", package)
+
+ os.makedirs(os.path.join(outd, "debian"), exist_ok=True)
+ build_changelog(outd, package)
+ for file in (
+ os.path.join("debian", "compat"),
+ os.path.join("debian", "copyright"),
+ os.path.join("debian", "source", "format"),
+ os.path.join("debian", "source", "options"),
+ ):
+ os.makedirs(os.path.dirname(os.path.join(outd, file)), exist_ok=True)
+ copy(file, os.path.join(outd, file))
+
+ # Convert debian/control: pull off and rename the source stanza, then add a
+ # simple build interlock package as we have to produce something.
+ in_control = os.path.join("debian", "control")
+ out_control = os.path.join(outd, "debian", "control.common")
+ with open(in_control) as ifd, open(out_control, "w") as ofd:
+ for line in ifd:
+ line = line.rstrip()
+ if len(line) == 0:
+ break
+ if line.startswith("Source:"):
+ line = f"Source: {package}"
+ elif package and package in line:
+ continue
+ print(line, file=ofd)
+
+ # Also dump out the files.json for -generate et al.
+ ancillary_dir = os.path.join("debian", "ancillary", package, "debian")
+ os.makedirs(ancillary_dir, exist_ok=True)
+ with open(os.path.join(ancillary_dir, "files.json"), "w") as ffd:
+ to_sign = {}
+ for (arch, flavour), (stype, binary) in signing.arch_flavour_data:
+ to_sign.setdefault("files", []).append({"sig_type": stype, "file": f"/boot/{binary}-{abi_version}-{flavour}", "arch": arch})
+ files = {package: to_sign}
+ json.dump(files, ffd, indent=2)
+
+
+abi_version, gen_pkg = sys.argv[1:]
+
+signing = Signing.load("debian/package.config")
+
+build_ancillary(gen_pkg)
Signed-off-by: Andy Whitcroft <apw@canonical.com> --- debian/ancillary/linux-generate/debian/rules | 8 ++ .../linux-generate/debian/scripts/gen-rules | 109 ++++++++++++++++++ debian/rules | 1 + debian/scripts/generate-control | 3 +- debian/scripts/parameterise-ancillaries | 78 +++++++++++++ 5 files changed, 198 insertions(+), 1 deletion(-) create mode 100755 debian/ancillary/linux-generate/debian/rules create mode 100755 debian/ancillary/linux-generate/debian/scripts/gen-rules create mode 100755 debian/scripts/parameterise-ancillaries