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}