#!/usr/bin/python3 # SPDX-License-Identifier: MIT """mdbp backend using pbuilder""" import argparse import contextlib import os import pathlib import shlex import subprocess import sys import tempfile import typing from .common import AddSpaceSeparatedValues, buildjson, clean_dir, \ compute_env, get_dsc, make_option, profile_option, \ temporary_static_file def find_basetgz(distribution: str, basedir: str = "/var/cache/pbuiler") -> typing.Optional[str]: """Locate a pbuilder base.tgz for the given distribution.""" if distribution in ("sid", "unstable"): return None for pat in ("/%s-base.tgz", "/%s.tgz"): basetgz = basedir + pat % distribution if pathlib.Path(basetgz).is_file(): return basetgz raise ValueError("unsupported distribution %s" % distribution) def main() -> None: """Entry point for mdbp-pbuilder backend""" parser = argparse.ArgumentParser() parser.add_argument( "--pbuilderopt", dest="pbuilderopts", action="append", metavar="OPT", default=[], help="a custom option to be passed down to pbuilder, can be specified " "multiple times and mixed with --pbuilderopts", ) parser.add_argument( "--pbuilderopts", action=AddSpaceSeparatedValues, metavar="OPTS", default=[], help="space-separated options to be passed down to pbuilder, can be " "specified multiple times and mixed with --pbuilderopt", ) parser.add_argument("buildjson", type=buildjson) args = parser.parse_args() build = args.buildjson if "sourcename" in build["input"]: raise ValueError("building a source package by name is not supported") enablelog = build["output"].get("log", True) if "bd-uninstallable-explainer" in build: raise ValueError("bd-uninstallable-explainer %r not supported" % build["bd-uinstallable-explainer"]) cmd = [ *([] if os.getuid() == 0 else ["sudo", "-E", "--"]), "/usr/sbin/pbuilder", "build", "--no-source-only-changes", *make_option("--basetgz", find_basetgz(build["distribution"])), *make_option("--architecture", build.get("build_architecture")), *make_option("--host-arch", build.get("host_architecture")), *make_option("--othermirror", "|".join(build.get("extrarepositories", ()))), *make_option("--use-network", {"enable": "yes", "try-enable": "yes", "disable": "no", "try-disable": "no"}.get(build.get("network"))), *dict(any=["--binary-arch"], all=["--binary-indep"], binary=["--debbuildopts", "-b"])[ build.get("type", "binary")], *profile_option(build, "--profiles"), "--buildresult", build["output"]["directory"], *([] if enablelog else ["--loglevel", "E"]), ] apt_get = ["apt-get", "-oAPT::Keep-Downloaded-Path=false", "--yes"] with contextlib.ExitStack() as stack: if build.get("build_path"): pbuilderrc = "BUILDDIR=%s\n" % shlex.quote(build["build_path"]) cmd.extend([ "--configfile", str(stack.enter_context(temporary_static_file(pbuilderrc))), ]) hookdir = pathlib.Path( stack.enter_context(tempfile.TemporaryDirectory())) hook = hookdir / "D50aptupdate" hook.write_text("""#/bin/sh set -e apt-get --error-on=any update %s dist-upgrade """ % shlex.join(apt_get)) hook.chmod(0o755) if build.get("lintian", {}).get("run", False): hook = hookdir / "B90lintian" hook.write_text("""#!/bin/sh set -e %s install lintian runuser -u pbuilder -- lintian %s "${BUILDDIR:-/tmp/buildd}"/*.changes """ % (shlex.join(apt_get), shlex.join(build["lintian"].get("options", [])))) hook.chmod(0o755) cmd.extend(["--hookdir", str(hookdir), *args.pbuilderopts, str(stack.enter_context(get_dsc(build)))]) ret = subprocess.call(cmd, env=compute_env(build), stdout=None if enablelog else subprocess.DEVNULL, stderr=subprocess.STDOUT if enablelog else subprocess.DEVNULL) clean_dir(pathlib.Path(build["output"]["directory"]), build["output"].get("artifacts", ["*"])) sys.exit(ret) if __name__ == "__main__": main()