diff mbox series

[10/13] UBUNTU: [Packaging] generate: add linux-generate as a direct ancillary

Message ID 20220916114642.2953019-11-apw@canonical.com
State New
Headers show
Series [01/13] UBUNTU: [Packaging] generate-depends: relocate to debian/scripts | expand

Commit Message

Andy Whitcroft Sept. 16, 2022, 11:46 a.m. UTC
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
diff mbox series

Patch

diff --git a/debian/ancillary/linux-generate/debian/rules b/debian/ancillary/linux-generate/debian/rules
new file mode 100755
index 0000000..7c00598
--- /dev/null
+++ b/debian/ancillary/linux-generate/debian/rules
@@ -0,0 +1,8 @@ 
+#! /usr/bin/make -f
+
+clean:
+	./debian/scripts/gen-rules
+	$(MAKE) -f debian/rules.gen clean
+
+%:
+	$(MAKE) -f debian/rules.gen $@
diff --git a/debian/ancillary/linux-generate/debian/scripts/gen-rules b/debian/ancillary/linux-generate/debian/scripts/gen-rules
new file mode 100755
index 0000000..628ab8c
--- /dev/null
+++ b/debian/ancillary/linux-generate/debian/scripts/gen-rules
@@ -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)
diff --git a/debian/rules b/debian/rules
index c957144..f55aa6b 100755
--- a/debian/rules
+++ b/debian/rules
@@ -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 				\
diff --git a/debian/scripts/generate-control b/debian/scripts/generate-control
index b0c3c15..3f8059d 100755
--- a/debian/scripts/generate-control
+++ b/debian/scripts/generate-control
@@ -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)
 
diff --git a/debian/scripts/parameterise-ancillaries b/debian/scripts/parameterise-ancillaries
new file mode 100755
index 0000000..b6dea0c
--- /dev/null
+++ b/debian/scripts/parameterise-ancillaries
@@ -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)