srtool_lib/
container_engine.rs

1use std::{fmt::Display, process::Command};
2
3use crate::SrtoolLibError;
4
5/// Represents the container engine being used.
6#[derive(Clone, Copy, PartialEq)]
7pub enum ContainerEngine {
8	/// Represents the Docker container engine.
9	Docker,
10	/// Represents the Podman container engine.
11	Podman,
12}
13
14impl ContainerEngine {
15	/// Check whether you have Podman and/or Docker installed. The default will be Podman if both are present.
16	pub fn detect() -> Result<ContainerEngine, SrtoolLibError> {
17		if let Ok(engine) = std::env::var("ENGINE") {
18			return ContainerEngine::try_from(engine.as_str());
19		}
20
21		let podman_output: Option<std::process::Output> = Command::new("podman").arg("--version").output().ok();
22		if let Some(podman) = podman_output {
23			let podman = String::from_utf8_lossy(&podman.stdout);
24			if podman.to_lowercase().contains("podman") {
25				return Ok(ContainerEngine::Podman);
26			} else if podman.contains("docker") {
27				return Ok(ContainerEngine::Docker);
28			}
29		}
30
31		let docker_output = Command::new("docker").arg("--version").output().ok();
32		if let Some(docker) = docker_output {
33			let docker = String::from_utf8_lossy(&docker.stdout);
34			if docker.to_lowercase().contains("docker") {
35				return Ok(ContainerEngine::Docker);
36			} else if docker.contains("podman") {
37				return Ok(ContainerEngine::Podman);
38			}
39		}
40
41		Err(SrtoolLibError::UnknownContainerEngine(None))
42	}
43}
44
45impl TryFrom<&str> for ContainerEngine {
46	type Error = SrtoolLibError;
47
48	fn try_from(s: &str) -> Result<Self, Self::Error> {
49		match s.to_ascii_lowercase().as_str() {
50			"auto" => Self::detect(),
51			"podman" => Ok(ContainerEngine::Podman),
52			"docker" => {
53				println!("WARNING: You are using docker. We recommend using podman instead.");
54				Ok(ContainerEngine::Docker)
55			}
56			_ => Err(SrtoolLibError::UnknownContainerEngine(Some(s.into()))),
57		}
58	}
59}
60
61impl Display for ContainerEngine {
62	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63		match self {
64			ContainerEngine::Docker => write!(f, "docker"),
65			ContainerEngine::Podman => write!(f, "podman"),
66		}
67	}
68}
69
70#[cfg(test)]
71mod tests {
72	use super::*;
73	use std::env;
74
75	#[test]
76	fn detect_works() {
77		env::set_var("ENGINE", "docker");
78		assert!(ContainerEngine::detect().unwrap() == ContainerEngine::Docker);
79
80		env::set_var("ENGINE", "podman");
81		assert!(ContainerEngine::detect().unwrap() == ContainerEngine::Podman);
82		// Cleanup after test
83		env::remove_var("ENGINE");
84	}
85
86	#[test]
87	fn container_enginer_try_from_works() {
88		assert!(ContainerEngine::try_from("docker").unwrap() == ContainerEngine::Docker);
89		assert!(ContainerEngine::try_from("podman").unwrap() == ContainerEngine::Podman);
90		assert!(matches!(ContainerEngine::try_from("invalid"), Err(SrtoolLibError::UnknownContainerEngine(Some(_)))));
91	}
92
93	#[test]
94	fn container_enginer_display_works() {
95		assert_eq!(ContainerEngine::Docker.to_string(), "docker");
96		assert_eq!(ContainerEngine::Podman.to_string(), "podman");
97	}
98}