diff --git a/dangerzone/container_utils.py b/dangerzone/container_utils.py
index 5794764..bbdb75a 100644
--- a/dangerzone/container_utils.py
+++ b/dangerzone/container_utils.py
@@ -5,6 +5,7 @@ import subprocess
from typing import List, Tuple
from . import errors
+from .settings import Settings
from .util import get_resource_path, get_subprocess_startupinfo
CONTAINER_NAME = "dangerzone.rocks/dangerzone"
@@ -13,14 +14,22 @@ log = logging.getLogger(__name__)
def get_runtime_name() -> str:
- if platform.system() == "Linux":
- runtime_name = "podman"
- else:
- # Windows, Darwin, and unknown use docker for now, dangerzone-vm eventually
- runtime_name = "docker"
+ settings = Settings()
+ try:
+ runtime_name = settings.get("container_runtime")
+ except KeyError:
+ return "podman" if platform.system() == "Linux" else "docker"
return runtime_name
+def get_runtime() -> str:
+ container_tech = get_runtime_name()
+ runtime = shutil.which(container_tech)
+ if runtime is None:
+ raise errors.NoContainerTechException(container_tech)
+ return runtime
+
+
def get_runtime_version() -> Tuple[int, int]:
"""Get the major/minor parts of the Docker/Podman version.
@@ -31,13 +40,14 @@ def get_runtime_version() -> Tuple[int, int]:
semver parser is an overkill.
"""
# Get the Docker/Podman version, using a Go template.
- runtime = get_runtime_name()
- if runtime == "podman":
+ runtime_name = get_runtime_name()
+
+ if runtime_name == "podman":
query = "{{.Client.Version}}"
else:
query = "{{.Server.Version}}"
- cmd = [runtime, "version", "-f", query]
+ cmd = [get_runtime(), "version", "-f", query]
try:
version = subprocess.run(
cmd,
@@ -46,7 +56,7 @@ def get_runtime_version() -> Tuple[int, int]:
check=True,
).stdout.decode()
except Exception as e:
- msg = f"Could not get the version of the {runtime.capitalize()} tool: {e}"
+ msg = f"Could not get the version of the {runtime.name.capitalize()} tool: {e}"
raise RuntimeError(msg) from e
# Parse this version and return the major/minor parts, since we don't need the
@@ -56,20 +66,12 @@ def get_runtime_version() -> Tuple[int, int]:
return (int(major), int(minor))
except Exception as e:
msg = (
- f"Could not parse the version of the {runtime.capitalize()} tool"
+ f"Could not parse the version of the {runtime_name.capitalize()} tool"
f" (found: '{version}') due to the following error: {e}"
)
raise RuntimeError(msg)
-def get_runtime() -> str:
- container_tech = get_runtime_name()
- runtime = shutil.which(container_tech)
- if runtime is None:
- raise errors.NoContainerTechException(container_tech)
- return runtime
-
-
def list_image_tags() -> List[str]:
"""Get the tags of all loaded Dangerzone images.
diff --git a/dangerzone/gui/main_window.py b/dangerzone/gui/main_window.py
index 9e4e23b..d162fcf 100644
--- a/dangerzone/gui/main_window.py
+++ b/dangerzone/gui/main_window.py
@@ -574,8 +574,15 @@ class WaitingWidgetContainer(WaitingWidget):
self.finished.emit()
def state_change(self, state: str, error: Optional[str] = None) -> None:
+ custom_runtime = self.dangerzone.settings.custom_runtime_specified()
+
if state == "not_installed":
- if platform.system() == "Linux":
+ if custom_runtime:
+ self.show_error(
+ "We could not find the container runtime defined in your settings
"
+ "Please check your settings, install it if needed, and retry."
+ )
+ elif platform.system() == "Linux":
self.show_error(
"Dangerzone requires Podman
"
"Install it and retry."
@@ -588,7 +595,12 @@ class WaitingWidgetContainer(WaitingWidget):
)
elif state == "not_running":
- if platform.system() == "Linux":
+ if custom_runtime:
+ self.show_error(
+ "We were unable to start the container runtime defined in your settings
"
+ "Please check your settings, install it if needed, and retry."
+ )
+ elif platform.system() == "Linux":
# "not_running" here means that the `podman image ls` command failed.
message = (
"Dangerzone requires Podman
"
diff --git a/dangerzone/settings.py b/dangerzone/settings.py
index 4c8b939..a10ad6b 100644
--- a/dangerzone/settings.py
+++ b/dangerzone/settings.py
@@ -39,6 +39,9 @@ class Settings:
"updater_errors": 0,
}
+ def custom_runtime_specified(self) -> bool:
+ return "container_runtime" in self.settings
+
def get(self, key: str) -> Any:
return self.settings[key]
diff --git a/tests/isolation_provider/test_container.py b/tests/isolation_provider/test_container.py
index 7f39664..797986e 100644
--- a/tests/isolation_provider/test_container.py
+++ b/tests/isolation_provider/test_container.py
@@ -87,7 +87,7 @@ class TestContainer(IsolationProviderTest):
) -> None:
"""When an image keep being not installed, it should return False"""
fp.register_subprocess(
- ["podman", "version", "-f", "{{.Client.Version}}"],
+ [container_utils.get_runtime(), "version", "-f", "{{.Client.Version}}"],
stdout="4.0.0",
)
diff --git a/tests/test_container_utils.py b/tests/test_container_utils.py
new file mode 100644
index 0000000..e921507
--- /dev/null
+++ b/tests/test_container_utils.py
@@ -0,0 +1,28 @@
+from pathlib import Path
+
+from pytest_mock import MockerFixture
+
+from dangerzone.container_utils import get_runtime_name
+from dangerzone.settings import Settings
+
+
+def test_get_runtime_name_from_settings(mocker: MockerFixture, tmp_path: Path) -> None:
+ mocker.patch("dangerzone.settings.get_config_dir", return_value=tmp_path)
+
+ settings = Settings()
+ settings.set("container_runtime", "new-kid-on-the-block", autosave=True)
+
+ assert get_runtime_name() == "new-kid-on-the-block"
+
+
+def test_get_runtime_name_linux(mocker: MockerFixture) -> None:
+ mocker.patch("platform.system", return_value="Linux")
+ assert get_runtime_name() == "podman"
+
+
+def test_get_runtime_name_non_linux(mocker: MockerFixture) -> None:
+ mocker.patch("platform.system", return_value="Windows")
+ assert get_runtime_name() == "docker"
+
+ mocker.patch("platform.system", return_value="Something else")
+ assert get_runtime_name() == "docker"