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