|
@@ -0,0 +1,171 @@
|
|
|
+#!/usr/bin/env python3
|
|
|
+
|
|
|
+import argparse
|
|
|
+import functools
|
|
|
+import operator
|
|
|
+import os
|
|
|
+import shutil
|
|
|
+import subprocess
|
|
|
+import time
|
|
|
+
|
|
|
+
|
|
|
+def system(cmd: str) -> None:
|
|
|
+ subprocess.run(cmd, shell=True, check=True)
|
|
|
+
|
|
|
+
|
|
|
+parser = argparse.ArgumentParser(usage="Build a patched Fedora kernel")
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--package-name",
|
|
|
+ help="The name of the patched package (e.g. foo -> kernel-foo).",
|
|
|
+ required=True,
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--package-tag",
|
|
|
+ help="The upstream tag to build.",
|
|
|
+ required=True,
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--package-release",
|
|
|
+ help="The release suffix of the modified package.",
|
|
|
+ required=True,
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--ark-dir",
|
|
|
+ help="The local path to the kernel-ark repository.",
|
|
|
+ default="kernel-ark",
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--ark-url",
|
|
|
+ help="The remote path to the kernel-ark repository.",
|
|
|
+ default="https://gitlab.com/cki-project/kernel-ark",
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--patch",
|
|
|
+ help="Applies a patch to the kernel source.",
|
|
|
+ action="append",
|
|
|
+ nargs="+",
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--config",
|
|
|
+ help="Applies a KConfig fragment to the kernel source.",
|
|
|
+ action="append",
|
|
|
+ nargs="+",
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--file",
|
|
|
+ help="Copy a file into the RPM buildroot.",
|
|
|
+ action="append",
|
|
|
+ nargs="+",
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--buildopts",
|
|
|
+ help="Enable or disable options of the kernel spec file.",
|
|
|
+ action="append",
|
|
|
+ nargs="+",
|
|
|
+)
|
|
|
+
|
|
|
+parser.add_argument(
|
|
|
+ "--outdir",
|
|
|
+ help="The directory where the built RPM files will be saved.",
|
|
|
+ default="out",
|
|
|
+)
|
|
|
+
|
|
|
+args = parser.parse_args()
|
|
|
+
|
|
|
+patches = [] if not args.patch else functools.reduce(operator.add, args.patch)
|
|
|
+configs = [] if not args.config else functools.reduce(operator.add, args.config)
|
|
|
+files = [] if not args.file else functools.reduce(operator.add, args.file)
|
|
|
+buildopts = [] if not args.buildopts else functools.reduce(operator.add, args.buildopts)
|
|
|
+
|
|
|
+# Make paths absolute.
|
|
|
+patches = [os.path.realpath(x) for x in patches]
|
|
|
+configs = [os.path.realpath(x) for x in configs]
|
|
|
+files = [os.path.realpath(x) for x in files]
|
|
|
+outdir = os.path.realpath(args.outdir)
|
|
|
+
|
|
|
+# Clone the kernel-ark repository if it doesn't exist.
|
|
|
+if not os.path.exists(args.ark_dir):
|
|
|
+ system("git clone '%s' '%s'" % (args.ark_url, args.ark_dir))
|
|
|
+
|
|
|
+os.chdir(args.ark_dir)
|
|
|
+
|
|
|
+# Check out the requested tag.
|
|
|
+system("git fetch --tags")
|
|
|
+system("git clean -dfx")
|
|
|
+system("git checkout -b 'build/%s'" % time.time())
|
|
|
+system("git reset --hard '%s'" % args.package_tag)
|
|
|
+
|
|
|
+# Apply patches
|
|
|
+for patch in patches:
|
|
|
+ system("git am '%s'" % patch)
|
|
|
+
|
|
|
+# Copy files
|
|
|
+for file in files:
|
|
|
+ shutil.copy(file, "redhat/fedora_files/")
|
|
|
+
|
|
|
+# Apply config options
|
|
|
+#
|
|
|
+# The format that the kernel-ark tree expects is a bit different from
|
|
|
+# a standard kernel config. Every option is split into a single file
|
|
|
+# named after that config.
|
|
|
+#
|
|
|
+# Example:
|
|
|
+# $ cat redhat/configs/common/generic/CONFIG_PCI
|
|
|
+# CONFIG_PCI=y
|
|
|
+#
|
|
|
+# This supposedly makes things easier for Red Hat developers,
|
|
|
+# but it also ends up being really annoying for us.
|
|
|
+for config in configs:
|
|
|
+ with open(config) as f:
|
|
|
+ lines = f.readlines()
|
|
|
+
|
|
|
+ # Filter out comments, this means only selecting lines that look like:
|
|
|
+ # - CONFIG_FOO=b
|
|
|
+ # - # CONFIG_FOO is not set
|
|
|
+ for line in lines:
|
|
|
+ enable = line.startswith("CONFIG_")
|
|
|
+ disable = line.startswith("# CONFIG_")
|
|
|
+
|
|
|
+ if not enable and not disable:
|
|
|
+ continue
|
|
|
+
|
|
|
+ NAME = ""
|
|
|
+
|
|
|
+ if enable:
|
|
|
+ NAME = line.split("=")[0]
|
|
|
+ elif disable:
|
|
|
+ NAME = line[2:].split(" ")[0]
|
|
|
+
|
|
|
+ print("Applying %s" % line.rstrip("\n"))
|
|
|
+
|
|
|
+ with open("redhat/configs/custom-overrides/generic/%s" % NAME, "w") as f:
|
|
|
+ f.write(line)
|
|
|
+
|
|
|
+system("git add redhat/configs/custom-overrides/generic")
|
|
|
+system("git commit -m 'Merge %s config'" % args.package_name)
|
|
|
+
|
|
|
+cmd = []
|
|
|
+cmd.append("make")
|
|
|
+cmd.append("dist-rpms")
|
|
|
+cmd.append("SPECPACKAGE_NAME='kernel-%s'" % args.package_name)
|
|
|
+cmd.append("DISTLOCALVERSION='.%s'" % args.package_name)
|
|
|
+cmd.append("BUILD='%s'" % args.package_release)
|
|
|
+
|
|
|
+if len(buildopts) > 0:
|
|
|
+ cmd.append("BUILDOPTS='%s'" % " ".join(buildopts))
|
|
|
+
|
|
|
+# Build RPMS
|
|
|
+system(" ".join(cmd))
|
|
|
+
|
|
|
+# Copy built RPMS to output directory
|
|
|
+os.makedirs(outdir, exist_ok=True)
|
|
|
+system("cp -r redhat/rpm/RPMS/* '%s'" % outdir)
|