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}