From 6049c435ca172211463f900b3cae59b9c8b03411 Mon Sep 17 00:00:00 2001 From: Damien Goutte-Gattat Date: Mon, 28 Sep 2026 23:14:49 +0100 Subject: [PATCH] Allow auto-detecting the default backend. Allow to (1) change the default backend from Docker to another backend, and (2) not specify any default backend at all, in which case the runner will try to auto-detect the backend to use. --- configure.ac | 15 +++++++++++++++ doc/odkrun.1.in | 6 ++++++ src/backend-apple.c | 1 - src/backend-apple.h | 6 ++++++ src/backend-docker.c | 1 - src/backend-docker.h | 3 +++ src/backend-native.h | 6 ++++++ src/backend-singularity.c | 1 - src/backend-singularity.h | 3 +++ src/odkrun.c | 24 ++++++++++++++++++++++-- src/procutil.c | 23 +++++++++++++++++++++++ src/procutil.h | 3 +++ 12 files changed, 87 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index e7ec94e..c6e971a 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,20 @@ AC_ARG_WITH([odk-executable], [with_odk_executable="/tools/odk.py"]) AC_DEFINE_UNQUOTED([ODK_EXECUTABLE], ["$with_odk_executable"], [Name or path of the odk script]) +dnl Default backend +AC_ARG_WITH([default-backend], + [AS_HELP_STRING([--with-default-backend], + [Name of the backend to use by default. One of docker, singularity, apple, native, or none.])], + [], + [with_default_backend=docker]) +AS_CASE([$with_default_backend], + [docker], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_docker_init], [Docker backend])], + [singularity], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_singularity_init], [Singularity backend])], + [apple], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_apple_init], [Apple Container backend])], + [native], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_native_init], [Native backend])], + [none], [AC_DEFINE([ODK_DEFAULT_BACKEND], [NULL], [No default backend])], + [AC_MSG_ERROR(["Unsupported backend: ${with_default_backend}"])]) + dnl Host-based tweaks AC_CANONICAL_HOST AS_CASE([$host], @@ -67,5 +81,6 @@ Configuration complete Host: '${host}' Compiler: '${CC} ${CFLAGS} ${CPPFLAGS}' +Default backend: '${with_default_backend}' " diff --git a/doc/odkrun.1.in b/doc/odkrun.1.in index 9c4c5a2..46b9c60 100644 --- a/doc/odkrun.1.in +++ b/doc/odkrun.1.in @@ -13,6 +13,7 @@ odkrun - ODK Runner tool .RB [ -t | --tag .IR tag ] .RB [ -l | --lite ] +.RB [ -D | --docker ] .RB [ -s | --singulary ] .RB [ --apple ] .RB [ -n | --native ] @@ -62,9 +63,14 @@ Use the \fIobolibrary/odklite\fR image. .SH BACKEND OPTIONS .TP +.BR -D ", " --docker +Run the container with Docker. This is normally the default +backend, unless specified otherwise at configure time. +.TP .BR -s ", " --singularity Run the container with Singularity rather than Docker. This is experimental but should mostly work. +.TP .BR --apple Run the container with Apple Container rather than Docker. This is only available on macOS. This is experimental but diff --git a/src/backend-apple.c b/src/backend-apple.c index bb2dcc3..081dc00 100644 --- a/src/backend-apple.c +++ b/src/backend-apple.c @@ -38,7 +38,6 @@ #include #include -#include "procutil.h" #include "util.h" #include "backend-docker.h" diff --git a/src/backend-apple.h b/src/backend-apple.h index 0ae6c85..b4c774a 100644 --- a/src/backend-apple.h +++ b/src/backend-apple.h @@ -40,6 +40,12 @@ extern "C" { int odk_backend_apple_init(odk_backend_t *); +#if defined(ODK_RUNNER_MACOS) +#define odk_backend_apple_available() check_process("container", "--version") +#else +#define odk_backend_apple_available() 0 +#endif + #ifdef __cpluscplus } #endif diff --git a/src/backend-docker.c b/src/backend-docker.c index bae5f59..b870ded 100644 --- a/src/backend-docker.c +++ b/src/backend-docker.c @@ -42,7 +42,6 @@ #include /* for getuid/getgid */ #endif -#include "procutil.h" #include "util.h" #define DOCKER_SSH_SOCKET "/run/host-services/ssh-auth.sock" diff --git a/src/backend-docker.h b/src/backend-docker.h index b35dea4..e362d19 100644 --- a/src/backend-docker.h +++ b/src/backend-docker.h @@ -34,6 +34,7 @@ #include #include "backend.h" +#include "procutil.h" #ifdef __cpluscplus extern "C" { @@ -45,6 +46,8 @@ odk_backend_docker_build_command(mem_registry_t *, odk_run_config_t *, char **); int odk_backend_docker_init(odk_backend_t *); +#define odk_backend_docker_available() check_process("docker", "--version") + #ifdef __cpluscplus } #endif diff --git a/src/backend-native.h b/src/backend-native.h index 5fba66f..e6b2cbc 100644 --- a/src/backend-native.h +++ b/src/backend-native.h @@ -40,6 +40,12 @@ extern "C" { int odk_backend_native_init(odk_backend_t *); +#if !defined(ODK_RUNNER_WINDOWS) +#define odk_backend_native_available() 1 +#else +#define odk_backend_native_available() 0 +#endif + #ifdef __cpluscplus } #endif diff --git a/src/backend-singularity.c b/src/backend-singularity.c index cc6895f..e602fd6 100644 --- a/src/backend-singularity.c +++ b/src/backend-singularity.c @@ -43,7 +43,6 @@ #include #include -#include "procutil.h" #include "util.h" #define SINGULARITY_SSH_SOCKET "/run/host-services/ssh-auth.sock" diff --git a/src/backend-singularity.h b/src/backend-singularity.h index a1efeb1..21136cf 100644 --- a/src/backend-singularity.h +++ b/src/backend-singularity.h @@ -32,6 +32,7 @@ #define ICP20240622_BACKEND_SINGULARITY_H #include "backend.h" +#include "procutil.h" #ifdef __cpluscplus extern "C" { @@ -40,6 +41,8 @@ extern "C" { int odk_backend_singularity_init(odk_backend_t *); +#define odk_backend_singularity_available() check_process("singularity", "--version") + #ifdef __cpluscplus } #endif diff --git a/src/odkrun.c b/src/odkrun.c index eec4fa7..4e20fc0 100644 --- a/src/odkrun.c +++ b/src/odkrun.c @@ -82,6 +82,8 @@ Start a ODK container.\n"); "); puts("Backend options:\n\ + -D, --docker Run the container with Docker. This is normally\n\ + the default.\n\ -s, --singulary Run the container with Singularity rather\n\ than Docker (experimental)."); #if defined(ODK_RUNNER_MACOS) @@ -449,7 +451,7 @@ main(int argc, char **argv) char *opt_value, *java_mem = NULL; odk_run_config_t cfg; odk_backend_t backend = { 0 }; - odk_backend_init backend_init = odk_backend_docker_init; + odk_backend_init backend_init = ODK_DEFAULT_BACKEND; struct option options[] = { { "help", 0, NULL, 'h' }, @@ -458,6 +460,7 @@ main(int argc, char **argv) { "image", 1, NULL, 'i' }, { "tag", 1, NULL, 't' }, { "lite", 0, NULL, 'l' }, + { "docker", 0, NULL, 'D' }, { "singularity", 0, NULL, 's' }, #if defined (ODK_RUNNER_MACOS) { "apple", 0, NULL, 'a' }, @@ -481,7 +484,7 @@ main(int argc, char **argv) odk_init_config(&cfg); - while ( (c = getopt_long(argc, argv, "+hvdi:t:lse:k:Km:" BACKEND_OPTS, + while ( (c = getopt_long(argc, argv, "+hvdi:t:lse:k:Km:D" BACKEND_OPTS, options, NULL)) != -1 ) { switch ( c ) { case 'h': @@ -513,6 +516,10 @@ main(int argc, char **argv) odk_set_image_name(&cfg, "obolibrary/odklite", 0); break; + case 'D': + backend_init = odk_backend_docker_init; + break; + case 's': backend_init = odk_backend_singularity_init; break; @@ -585,6 +592,19 @@ main(int argc, char **argv) #endif } + if ( ! backend_init ) { + if ( odk_backend_docker_available() ) + backend_init = odk_backend_docker_init; + else if ( odk_backend_singularity_available() ) + backend_init = odk_backend_singularity_init; + else if ( odk_backend_apple_available() ) + backend_init = odk_backend_apple_init; + else if ( odk_backend_native_available() ) + backend_init = odk_backend_native_init; + else + errx(EXIT_FAILURE, "No backend specified"); + } + if ( backend_init(&backend) == -1 ) err(EXIT_FAILURE, "Cannot initialise backend"); diff --git a/src/procutil.c b/src/procutil.c index 4dc1a2c..b29214d 100644 --- a/src/procutil.c +++ b/src/procutil.c @@ -116,3 +116,26 @@ spawn_process(char **argv) #endif return -1; } + +/** + * Spawns a process and checks that it exits with a non-error status. + * This is primarily intended to check whether a given command is + * available on the system's PATH. + * + * @param command The command to run. + * @param argument A single argument for the command. May be NULL. + * + * @return A non-zero value if the process executed and returned + * normally, otherwise zero. + */ +int +check_process(const char *command, const char *argument) +{ + char *argv[3]; + + argv[0] = (char *)command; + argv[1] = (char *)argument; + argv[2] = NULL; + + return spawn_process(argv) == 0; +} diff --git a/src/procutil.h b/src/procutil.h index bea8d2f..1846806 100644 --- a/src/procutil.h +++ b/src/procutil.h @@ -38,6 +38,9 @@ extern "C" { int spawn_process(char **); +int +check_process(const char *, const char *); + #ifdef __cplusplus } #endif