#!/usr/bin/python3 # SPDX-License-Identifier: MIT """mdbp backend using sbuild""" import argparse import contextlib import subprocess import sys import tempfile import typing from .common import buildjson, compute_env, get_dsc PerlValue = typing.Union[None, str, typing.List[typing.Any], typing.Dict[str, typing.Any]] def perl_repr(value: PerlValue) -> str: """Encode a Python value as a string parseable to Perl.""" if value is None: return "undef" if isinstance(value, bool): return str(int(value)) if isinstance(value, str): return '"%s"' % value \ .replace("\\", r"\\") \ .replace('"', r'\"') \ .replace("\n", r"\n") \ .replace("\r", r"\r") if isinstance(value, list): return "[%s]" % ",".join(map(perl_repr, value)) if isinstance(value, dict): return "{%s}" % ",".join("%s => %s" % (perl_repr(key), perl_repr(value)) for key, value in value.items()) raise TypeError("unexpected value type %r" % type(value)) def perl_conf(conf: typing.Dict[str, PerlValue]) -> str: """Turn a mapping into a Perl source assigning variables.""" return "".join("$%s=%s;\n" % (key, perl_repr(value)) for key, value in conf.items()) + "1;\n" def main() -> None: """Entry point for mdbp-sbuild backend""" parser = argparse.ArgumentParser() parser.add_argument("buildjson", type=buildjson) args = parser.parse_args() build = args.buildjson if build.get("network") == "disable": raise ValueError("disabling network not supported with sbuild") sbc = dict( nolog=True, distribution=build["distribution"], build_arch_all=build.get("type") != "any", build_arch_any=build.get("type") != "all", bd_uninstallable_explainer=build.get("bd-uninstallable-explainer", ""), run_lintian=bool(build.get("lintian", {}).get("run")), extra_repositories=build.get("extra_repositories", []), build_environment=compute_env(build), external_commands={}) with contextlib.suppress(KeyError): sbc["lintian_opts"] = build["lintian"]["options"] with contextlib.suppress(KeyError): sbc["build_arch"] = build["buildarch"] with contextlib.suppress(KeyError): sbc["host_arch"] = build["hostarch"] with contextlib.suppress(KeyError): sbc["build_profiles"] = " ".join(build["profiles"]) with contextlib.suppress(KeyError): sbc["build_path"] = build["buildpath"] if build.get("network") == "try-disable": sbc["external_commands"]["starting-build-commands"] = \ ["mv /etc/resolv.conf /etc/resolv.conf.disabled"] sbc["external_commands"]["finished-build-commands"] = \ ["mv /etc/resolv.conf.disabled /etc/resolv.conf"] with tempfile.NamedTemporaryFile(mode="w") as sbuildconf, \ get_dsc(build) as dscpath: sbuildconf.write(perl_conf(sbc)) sbuildconf.flush() proc = subprocess.Popen(["sbuild", str(dscpath.absolute())], env=dict(SBUILD_CONFIG=sbuildconf.name, PATH="/usr/bin:/bin"), cwd=build["output"]["directory"], stdout=None if build["output"].get("log", True) else subprocess.DEVNULL, stderr=subprocess.STDOUT if build["output"].get("log", True) else subprocess.DEVNULL) sys.exit(proc.wait()) if __name__ == "__main__": main()