vdev/testing/
docker.rs

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