On 7/14/2026 4:40 AM, Daniel P. Berrangé wrote: > The '--engine' arg accepts either 'podman' or 'docker', which is > not sufficiently granular to map directly to a command. This > means that docker.py still has to then probe the exact command > to use. > > Meanwhile the 'probe' command prints out the full command to use > but this cannot be passed back to docker.py to avoid probing > again, so the caching is only useful in the few case where we > run a container directly bypassing docker.py. > > Address this by replacing --engine with --command for docker.py. > > This in turn requires the --container-engine configure arg to be > replaced with --container-command. > > With these changes the container command is probed at most once > during configure and never again, while running in an unconfigured > tree will still probe on demand. > > Signed-off-by: Daniel P. Berrangé <[email protected]> > --- > configure | 24 ++++++------- > tests/docker/Makefile.include | 13 ++++--- > tests/docker/docker.py | 67 ++++++++++++----------------------- > 3 files changed, 39 insertions(+), 65 deletions(-) > > diff --git a/configure b/configure > index d8bc10060e..6602fc3004 100755 > --- a/configure > +++ b/configure > @@ -172,7 +172,7 @@ fi > # some defaults, based on the host environment > > # default parameters > -container_engine="auto" > +container_command="" > cpu="" > cross_compile="no" > cross_prefix="" > @@ -734,7 +734,7 @@ for opt do > ;; > --disable-containers) use_containers="no" > ;; > - --container-engine=*) container_engine="$optarg" > + --container-command=*) container_command="$optarg" > ;; > --rust-target-triple=*) rust_target_triple="$optarg" > ;; > @@ -869,7 +869,7 @@ Advanced options (experts only): > --enable-debug enable common debug build options > --cpu=CPU Build for host CPU [$cpu] > --disable-containers don't use containers for cross-building > - --container-engine=TYPE which container engine to use [$container_engine] > + --container-command=CMD which container command to use [autodetect] > --gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin] > --wasm64-32bit-address-limit Restrict wasm64 address space to 32-bit > (default > is to use the whole 64-bit range). > @@ -1291,12 +1291,11 @@ fi > ########################################## > # functions to probe cross compilers > > -runc="no" > -if test $use_containers = "yes" && (has "docker" || has "podman"); then > - runc=$($python "$source_path"/tests/docker/docker.py --engine > "$container_engine" probe) > - if test "$runc" != "no"; then > - docker_py="$python $source_path/tests/docker/docker.py --engine > $container_engine" > - fi > +if test "$container_command" = ""; then > + container_command=$($python "$source_path"/tests/docker/docker.py probe) > +fi > +if test $use_containers = "yes" && test "$container_command" != ""; then > + docker_py="$python $source_path/tests/docker/docker.py --command > $container_command" > fi > > # cross compilers defaults, can be overridden with --cross-cc-ARCH > @@ -1415,7 +1414,7 @@ probe_target_compiler() { > esac > > for host in $container_hosts; do > - test "$runc" != no || continue > + test "$container_command" != "" || continue > test "$host" = "$cpu" || continue > case $target_arch in > # debian-all-test-cross architectures > @@ -1736,9 +1735,8 @@ echo all: >> $config_host_mak > echo "SRC_PATH=$source_path" >> $config_host_mak > echo "TARGET_DIRS=$target_list" >> $config_host_mak > echo "GDB=$gdb_bin" >> $config_host_mak > -if test "$runc" != no; then > - echo "RUNC=$runc" >> $config_host_mak > - echo "CONTAINER_ENGINE=$container_engine" >> $config_host_mak > +if test "$container_command" != ""; then > + echo "CONTAINER_COMMAND=$container_command" >> $config_host_mak > fi > echo "SUBDIRS=$subdirs" >> $config_host_mak > if test "$rust" != disabled; then > diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include > index 4725c39807..0adddb6a5c 100644 > --- a/tests/docker/Makefile.include > +++ b/tests/docker/Makefile.include > @@ -16,9 +16,8 @@ DOCKER_DEFAULT_REGISTRY := > registry.gitlab.com/qemu-project/qemu > endif > DOCKER_REGISTRY := $(if $(REGISTRY),$(REGISTRY),$(DOCKER_DEFAULT_REGISTRY)) > > -CONTAINER_ENGINE = auto > -DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(CONTAINER_ENGINE) > -RUNC ?= $(shell $(DOCKER_SCRIPT) probe) > +CONTAINER_COMMAND ?= $(shell $(SRC_PATH)/tests/docker/docker.py probe) > +DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --command > "$(CONTAINER_COMMAND)" > > CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) > DOCKER_SRC_COPY := $(BUILD_DIR)/docker-src.$(CUR_TIME) > @@ -41,7 +40,7 @@ docker-qemu-src: $(DOCKER_SRC_COPY) > # General rule for building docker images. > docker-image-%: $(DOCKER_FILES_DIR)/%.docker > $(call quiet-command, \ > - DOCKER_BUILDKIT=1 $(RUNC) build \ > + DOCKER_BUILDKIT=1 $(CONTAINER_COMMAND) build \ > $(if $(DOCKER_V),,--quiet) \ > $(if $(NOCACHE),--no-cache, \ > $(if $(DOCKER_REGISTRY),--cache-from > $(DOCKER_REGISTRY)/qemu/$*)) \ > @@ -152,7 +151,7 @@ $(foreach i,$(filter-out > $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES)), \ > ) > > docker: > - @echo 'Build QEMU and run tests inside $(RUNC) containers' > + @echo 'Build QEMU and run tests inside $(CONTAINER_COMMAND) containers' > @echo > @echo 'Available targets:' > @echo > @@ -219,10 +218,10 @@ docker-run: docker-qemu-src > $(IMAGE) --executable $(EXECUTABLE), \ > " COPYING $(EXECUTABLE) to $(IMAGE)")) > $(call quiet-command, \ > - $(RUNC) run \ > + $(CONTAINER_COMMAND) run \ > --rm \ > $(if $(NOUSER),, \ > - $(if $(filter docker,$(RUNC)), \ > + $(if $(filter docker,$(CONTAINER_COMMAND)), \ > -u $(UID), \ > --userns keep-id \ > ) \ > diff --git a/tests/docker/docker.py b/tests/docker/docker.py > index 9e18b984f4..d2f39b5645 100755 > --- a/tests/docker/docker.py > +++ b/tests/docker/docker.py > @@ -35,27 +35,6 @@ > > DEVNULL = open(os.devnull, 'wb') > > -class EngineEnum(enum.IntEnum): > - AUTO = 1 > - DOCKER = 2 > - PODMAN = 3 > - > - def __str__(self): > - return self.name.lower() > - > - def __repr__(self): > - return str(self) > - > - @staticmethod > - def argparse(s): > - try: > - return EngineEnum[s.upper()] > - except KeyError: > - return s > - > - > -USE_ENGINE = EngineEnum.AUTO > - > def _bytes_checksum(bytes): > """Calculate a digest string unique to the text content""" > return hashlib.sha1(bytes).hexdigest() > @@ -73,12 +52,11 @@ def _file_checksum(filename): > > def _guess_engine_command(): > """ Guess a working engine command or raise exception if not found""" > - commands = [] > - > - if USE_ENGINE in [EngineEnum.AUTO, EngineEnum.PODMAN]: > - commands += [["podman"], ["podman-remote"], ["podman", "--remote"]] > - if USE_ENGINE in [EngineEnum.AUTO, EngineEnum.DOCKER]: > - commands += [["docker"], ["sudo", "-n", "docker"]] > + commands = [["podman"], > + ["podman-remote"], > + ["podman", "--remote"], > + ["docker"], > + ["sudo", "-n", "docker"]] > for cmd in commands: > try: > # 'version' is not sufficient to prove a working binary > @@ -222,8 +200,11 @@ def _dockerfile_verify_flat(df): > > class Docker(object): > """ Running Docker commands """ > - def __init__(self): > - self._command = _guess_engine_command() > + def __init__(self, commandstr=None): > + if commandstr is None: > + self._command = _guess_engine_command() > + else: > + self._command = commandstr.split(" ") > > if ("docker" in self._command and > "TRAVIS" not in os.environ and > @@ -411,8 +392,8 @@ def args(self, parser): > help="Run container using the current user's > uid") > > def run(self, args, argv): > - return Docker().run(argv, args.keep, quiet=args.quiet, > - as_user=args.run_as_current_user) > + return Docker(args.command).run(argv, args.keep, quiet=args.quiet, > + as_user=args.run_as_current_user) > > > class BuildCommand(SubCommand): > @@ -445,7 +426,7 @@ def run(self, args, argv): > dockerfile = _read_dockerfile(args.dockerfile) > tag = args.tag > > - dkr = Docker() > + dkr = Docker(args.command) > if "--no-cache" not in argv and \ > dkr.image_matches_dockerfile(tag, dockerfile): > if not args.quiet: > @@ -512,7 +493,7 @@ def args(self, parser): > help="Docker registry") > > def run(self, args, argv): > - dkr = Docker() > + dkr = Docker(args.command) > dkr.command(cmd="pull", quiet=args.quiet, > argv=["%s/%s" % (args.registry, args.tag)]) > dkr.command(cmd="tag", quiet=args.quiet, > @@ -590,7 +571,7 @@ def run(self, args, argv): > tmp.seek(0) > > # Run the build with our tarball context > - dkr = Docker() > + dkr = Docker(args.command) > dkr.update_image(args.tag, tmp, quiet=args.quiet) > > return 0 > @@ -601,7 +582,7 @@ class CleanCommand(SubCommand): > name = "clean" > > def run(self, args, argv): > - Docker().clean() > + Docker(args.command).clean() > return 0 > > > @@ -610,7 +591,7 @@ class ImagesCommand(SubCommand): > name = "images" > > def run(self, args, argv): > - return Docker().command("images", argv, args.quiet) > + return Docker(args.command).command("images", argv, args.quiet) > > > class ProbeCommand(SubCommand): > @@ -619,7 +600,7 @@ class ProbeCommand(SubCommand): > > def run(self, args, argv): > try: > - docker = Docker() > + docker = Docker(args.command) > print(" ".join(docker._command)) > except Exception: > print("no") > @@ -651,18 +632,16 @@ def run(self, args, argv): > cmd += ["-v", "%s:%s:ro,z" % (p, p)] > cmd += [args.image, args.cc] > cmd += argv > - return Docker().run(cmd, False, quiet=args.quiet, > - as_user=True) > + return Docker(args.command).run(cmd, False, quiet=args.quiet, > + as_user=True) > > > def main(): > - global USE_ENGINE > - > parser = argparse.ArgumentParser(description="A Docker helper", > usage="%s <subcommand> ..." % > os.path.basename(sys.argv[0])) > - parser.add_argument("--engine", type=EngineEnum.argparse, > choices=list(EngineEnum), > - help="specify which container engine to use") > + parser.add_argument("--command", > + help="specify which container engine command to use") > subparsers = parser.add_subparsers(title="subcommands", help=None) > for cls in SubCommand.__subclasses__(): > cmd = cls() > @@ -671,8 +650,6 @@ def main(): > cmd.args(subp) > subp.set_defaults(cmdobj=cmd) > args, argv = parser.parse_known_args() > - if args.engine: > - USE_ENGINE = args.engine > return args.cmdobj.run(args, argv) > >
This looks good, but it fails to run tcg-tests on a machine without podman/docker, with error message: bash: line 1: no: command not found You can include this patch in your series: https://lore.kernel.org/qemu-devel/[email protected]/ and detect if probe command worked or failed, and adapt behavior based on it. Regards, Pierrick
