vdev/testing/
docker.rs

1use std::env;
2use std::ffi::{OsStr, OsString};
3use std::path::PathBuf;
4use std::process::{Command, Stdio};
5use std::sync::LazyLock;
6
7pub static CONTAINER_TOOL: LazyLock<OsString> =
8    LazyLock::new(|| env::var_os("CONTAINER_TOOL").unwrap_or_else(detect_container_tool));
9
10pub(super) static DOCKER_SOCKET: LazyLock<PathBuf> = LazyLock::new(detect_docker_socket);
11
12pub fn docker_command<I: AsRef<OsStr>>(args: impl IntoIterator<Item = I>) -> Command {
13    let mut command = Command::new(&*CONTAINER_TOOL);
14    command.args(args);
15    command
16}
17
18fn detect_container_tool() -> OsString {
19    for tool in ["docker", "podman"] {
20        if Command::new(tool)
21            .arg("version")
22            .stdout(Stdio::null())
23            .stderr(Stdio::null())
24            .spawn()
25            .and_then(|mut child| child.wait())
26            .is_ok_and(|status| status.success())
27        {
28            return OsString::from(String::from(tool));
29        }
30    }
31    fatal!("No container tool could be detected.");
32}
33
34fn detect_docker_socket() -> PathBuf {
35    match env::var_os("DOCKER_HOST") {
36        Some(host) => host
37            .into_string()
38            .expect("Invalid value in $DOCKER_HOST")
39            .strip_prefix("unix://")
40            .expect("$DOCKER_HOST is not a socket path")
41            .into(),
42        None => "/var/run/docker.sock".into(),
43    }
44}