summaryrefslogtreecommitdiffstats
path: root/bin/sbuild-qemu
diff options
context:
space:
mode:
Diffstat (limited to 'bin/sbuild-qemu')
-rwxr-xr-xbin/sbuild-qemu190
1 files changed, 190 insertions, 0 deletions
diff --git a/bin/sbuild-qemu b/bin/sbuild-qemu
new file mode 100755
index 0000000..52ab6ff
--- /dev/null
+++ b/bin/sbuild-qemu
@@ -0,0 +1,190 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright © 2020-2024 Christian Kastner <ckk@debian.org>
+# 2024 Johannes Schauer Marin Rodrigues <josch@debian.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+#######################################################################
+
+
+import argparse
+import os
+import subprocess
+import sys
+
+
+DEB_ARCH_TO_QEMU = {
+ 'amd64': 'x86_64',
+ 'arm64': 'aarch64',
+ 'armhf': 'arm',
+ 'i386': 'i386',
+ 'ppc64el': 'ppc64le',
+}
+
+IMAGEDIR = os.environ.get(
+ 'IMAGEDIR',
+ os.path.join(os.path.expanduser('~'), '.cache', 'sbuild'),
+)
+
+DEFAULT_ARCH = subprocess.check_output(
+ ['dpkg', '--print-architecture'],
+ text=True,
+).strip()
+
+
+def main():
+ # init options
+ parser = argparse.ArgumentParser(
+ description="Build Debian packages with sbuild(1) using QEMU images",
+ epilog="All options other than the ones described below are passed on "
+ "through to sbuild(1), though the options --dist, --arch, and "
+ "--build are peeked at when looking for images. The image will "
+ "be started in snapshot mode, so the image is never modified. "
+ "Multiple processes can use the same image concurrently. The "
+ "architectures currently supported by sbuild-qemu are: "
+ f"{', '.join(DEB_ARCH_TO_QEMU.keys())}.",
+ )
+ parser.add_argument(
+ '--image',
+ action='store',
+ help="QEMU image file to use for building. If not specified, "
+ "sbuild-qemu will look for an image with the name "
+ "DIST-autopkgtest-ARCH.img, where DIST is taken from --dist "
+ "if present, and ARCH is taken from --arch or --build if "
+ "present. Otherwise, DIST defaults to 'unstable', and ARCH to "
+ "the host architecture. sbuild-qemu will first look in the "
+ "current directory for such an image, and then in the directory "
+ "$IMAGEDIR. A suitable image can be created with "
+ "qemu-sbuild-create(1).",
+ )
+ parser.add_argument(
+ '--ram-size',
+ metavar='MiB',
+ action='store',
+ default=2048,
+ help=f"VM memory size in MB. Default: 2048",
+ )
+ parser.add_argument(
+ '--cpus',
+ metavar='CPUs',
+ action='store',
+ default=2,
+ help="VM CPU count. Default: 2",
+ )
+ parser.add_argument(
+ '--overlay-dir',
+ action='store',
+ default='/tmp',
+ help="Directory for the temporary image overlay instead of "
+ "autopkgtest's default of /tmp (or $TMPDIR).",
+ )
+ parser.add_argument(
+ '--noexec',
+ action='store_true',
+ help="Don't actually do anything. Just print the sbuild(1) command "
+ "string that would be executed, and then exit.",
+ )
+ parser.add_argument(
+ '--autopkgtest-debug',
+ action='store_true',
+ help="Enable debug output for the autopkgtest-virt-qemu(1) driver.",
+ )
+ parser.add_argument(
+ '--boot',
+ choices=['auto', 'bios', 'efi', 'ieee1275', 'none'],
+ default='auto',
+ help="How to boot the image. Default is BIOS on amd64 and i386, EFI "
+ "on arm64 and armhf, and IEEE1275 on ppc64el.",
+ )
+ parsed_args, unparsed_args = parser.parse_known_args()
+
+ # These aren't options for us specifically, but we use them for guessing
+ # image locations
+ peeker = argparse.ArgumentParser()
+ peeker.add_argument(
+ '--dist',
+ action='store',
+ default='unstable',
+ )
+ peeker.add_argument(
+ '--arch',
+ action='store',
+ default=DEFAULT_ARCH,
+ )
+ peeker.add_argument(
+ '--build',
+ action='store',
+ )
+ peeked_args, _ = peeker.parse_known_args(unparsed_args)
+
+ build_arch = peeked_args.build or peeked_args.arch
+ try:
+ qemu_arch = DEB_ARCH_TO_QEMU[build_arch]
+ except KeyError:
+ print(f"Unsupported architecture: {build_arch}", file=sys.stderr)
+ print("Supported architectures are: ", file=sys.stderr, end="")
+ print(f"{', '.join(DEB_ARCH_TO_QEMU.keys())}", file=sys.stderr)
+ sys.exit(1)
+
+ if parsed_args.image:
+ if os.path.exists(os.path.abspath(parsed_args.image)):
+ image = parsed_args.image
+ else:
+ image = os.path.join(IMAGEDIR, parsed_args.image)
+ else:
+ guessed_name = f'{peeked_args.dist}-autopkgtest-{build_arch}.img'
+ if os.path.exists(os.path.abspath(guessed_name)):
+ images = os.path.abspath(guessed_name)
+ else:
+ image = os.path.join(
+ IMAGEDIR,
+ f'{peeked_args.dist}-autopkgtest-{build_arch}.img',
+ )
+
+ if not os.path.exists(image):
+ print(f"File {image} does not exist.", file=sys.stderr)
+ sys.exit(1)
+
+ args = [
+ 'sbuild',
+ '--dist', peeked_args.dist,
+ '--purge-build=never',
+ '--purge-deps=never',
+ '--chroot-mode=autopkgtest',
+ '--autopkgtest-virt-server=qemu',
+ '--autopkgtest-virt-server-opt', f'--overlay-dir={parsed_args.overlay_dir}',
+ '--autopkgtest-virt-server-opt', f'--qemu-architecture={qemu_arch}',
+ '--autopkgtest-virt-server-opt', f'--ram-size={parsed_args.ram_size}',
+ '--autopkgtest-virt-server-opt', f'--cpus={parsed_args.cpus}',
+ '--autopkgtest-virt-server-opt', f'--boot={parsed_args.boot}',
+ '--autopkgtest-virt-server-opt', image,
+ # Worarkound -- dose can hang stuff in a qemu VM
+ '--bd-uninstallable-explainer', 'apt',
+ ]
+ if parsed_args.autopkgtest_debug:
+ args += ['--autopkgtest-virt-server-opt', '--debug']
+
+ # Pass on the remaining (before peeking) arguments to sbuild
+ args += unparsed_args
+
+ print(' '.join(str(a) for a in args))
+ if not parsed_args.noexec:
+ os.execvp(args[0], args)
+
+
+if __name__ == '__main__':
+ main()