#!/usr/bin/env python3 import argparse import datetime import os import shutil import subprocess import sys import tempfile from jinja2 import Environment, FileSystemLoader def version_str() -> str: try: return subprocess.check_output(["git", "describe"]).strip().decode("utf-8") except subprocess.CalledProcessError: return "0" def prep_tree(package) -> tuple: tmpdir = tempfile.mkdtemp() builddir = os.path.join(tmpdir, package) fwdir = os.path.join(builddir, "updates") targetdir = "dist" os.makedirs(targetdir, exist_ok=True) os.makedirs(builddir, exist_ok=False) os.makedirs(fwdir, exist_ok=False) subprocess.check_output(["./copy-firmware.sh", fwdir]) shutil.copy("WHENCE", os.path.join(builddir, "WHENCE")) return (tmpdir, builddir, fwdir, targetdir) def build_deb_package(package, builddir) -> None: env = Environment(loader=FileSystemLoader(os.path.join("contrib", "templates"))) d = { "package": package, "date": datetime.datetime.now() .astimezone() .strftime("%a, %d %b %Y %H:%M:%S %z"), "version": version_str(), } templates = { "debian.control": "control", "debian.changelog": "changelog", "debian.copyright": "copyright", } os.makedirs(os.path.join(builddir, "debian")) for f in templates: template = env.get_template(f) with open(os.path.join(builddir, "debian", templates[f]), "w") as w: w.write(template.render(d)) with open(os.path.join(builddir, "debian", "install"), "w") as w: w.write("updates lib/firmware\n") with open(os.path.join(builddir, "debian", "docs"), "w") as w: w.write("WHENCE\n") with open(os.path.join(builddir, "debian", "rules"), "w") as w: w.write("#!/usr/bin/make -f\n") w.write("%:\n") w.write("\tdh $@\n") os.chmod(os.path.join(builddir, "debian", "rules"), 0o755) os.mkdir(os.path.join(builddir, "debian", "source")) with open(os.path.join(builddir, "debian", "source", "format"), "w") as w: w.write("3.0 (native)\n") # build the package os.environ["DEB_BUILD_OPTIONS"] = "nostrip" subprocess.check_output(["dpkg-buildpackage", "-us", "-uc", "-b"], cwd=builddir) # result is in tmpdir (not builddir!) return os.path.join( "..", "{package}_{version}_all.deb".format(package=package, version=version_str()), ) def build_rpm_package(package, builddir) -> None: v = version_str().replace("-", "_") env = Environment(loader=FileSystemLoader(os.path.join("contrib", "templates"))) d = { "package": package, "version": v, "cwd": builddir, } template = env.get_template("rpm.spec") with open(os.path.join(builddir, "package.spec"), "wt") as w: w.write(template.render(d)) cmd = ["rpmbuild", "-bb", "--build-in-place", "package.spec"] subprocess.check_call(cmd, cwd=builddir, stderr=subprocess.STDOUT) # result is in ~/rpmbuild/RPMS/noarch/ for root, dirs, files in os.walk( os.path.join(os.getenv("HOME"), "rpmbuild", "RPMS", "noarch") ): for f in files: if f.startswith(package) and f.endswith(".rpm") and v in f: return os.path.join(root, f) raise FileNotFoundError("RPM package not found") def parse_args(): parser = argparse.ArgumentParser("Build upstream packages using Jinja2 templates") parser.add_argument("--deb", help="Build DEB package", action="store_true") parser.add_argument("--rpm", help="Build RPM package", action="store_true") parser.add_argument("--debug", help="Enable debug output", action="store_true") args = parser.parse_args() if not (args.rpm or args.deb) or (args.rpm and args.deb): parser.print_help() sys.exit(1) return args if __name__ == "__main__": args = parse_args() package = "linux-firmware-upstream" tmpdir, builddir, fwdir, targetdir = prep_tree(package) try: if args.deb: result = build_deb_package(package, builddir) elif args.rpm: result = build_rpm_package(package, builddir) shutil.copy(os.path.join(builddir, result), targetdir) print( "Built package: {}".format( os.path.join(targetdir, os.path.basename(result)) ) ) finally: if not args.debug: shutil.rmtree(tmpdir)