Add a set-container-runtime option to dangerzone-cli

This sets the container runtime in the settings, and provides an easy
way to do so for users, without having to mess with the json settings.

When setting the container runtime, one can just pass "podman" and the
path to the executable will be stored in the settings.
This commit is contained in:
Alexis Métaireau 2025-03-28 13:31:23 +01:00
parent 86eab5d222
commit 0a7b79f61a
No known key found for this signature in database
GPG key ID: C65C7A89A8FFC56E
5 changed files with 56 additions and 13 deletions

View file

@ -11,6 +11,7 @@ from .isolation_provider.container import Container
from .isolation_provider.dummy import Dummy
from .isolation_provider.qubes import Qubes, is_qubes_native_conversion
from .logic import DangerzoneCore
from .settings import Settings
from .util import get_version, replace_control_chars
@ -37,7 +38,7 @@ def print_header(s: str) -> None:
)
@click.argument(
"filenames",
required=True,
required=False,
nargs=-1,
type=click.UNPROCESSED,
callback=args.validate_input_filenames,
@ -48,17 +49,33 @@ def print_header(s: str) -> None:
flag_value=True,
help="Run Dangerzone in debug mode, to get logs from gVisor.",
)
@click.option(
"--set-container-runtime",
required=False,
help="The path to the container runtime you want to set in the settings",
)
@click.version_option(version=get_version(), message="%(version)s")
@errors.handle_document_errors
def cli_main(
output_filename: Optional[str],
ocr_lang: Optional[str],
filenames: List[str],
filenames: Optional[List[str]],
archive: bool,
dummy_conversion: bool,
debug: bool,
set_container_runtime: Optional[str] = None,
) -> None:
setup_logging()
display_banner()
if set_container_runtime:
settings = Settings()
container_runtime = settings.set_custom_runtime(
set_container_runtime, autosave=True
)
click.echo(f"Set the settings container_runtime to {container_runtime}")
sys.exit(0)
elif not filenames:
raise click.UsageError("Missing argument 'FILENAMES...'")
if getattr(sys, "dangerzone_dev", False) and dummy_conversion:
dangerzone = DangerzoneCore(Dummy())
@ -67,7 +84,6 @@ def cli_main(
else:
dangerzone = DangerzoneCore(Container(debug=debug))
display_banner()
if len(filenames) == 1 and output_filename:
dangerzone.add_document_from_filename(filenames[0], output_filename, archive)
elif len(filenames) > 1 and output_filename:

View file

@ -16,6 +16,14 @@ log = logging.getLogger(__name__)
class Runtime(object):
"""Represents the container runtime to use.
- It can be specified via the settings, using the "container_runtime" key,
which should point to the full path of the runtime;
- If the runtime is not specified via the settings, it defaults
to "podman" on Linux and "docker" on macOS and Windows.
"""
def __init__(self) -> None:
settings = Settings()
@ -26,14 +34,22 @@ class Runtime(object):
self.name = self.path.stem
else:
self.name = self.get_default_runtime_name()
binary_path = shutil.which(self.name)
if binary_path is None or not os.path.exists(binary_path):
raise errors.NoContainerTechException(self.name)
self.path = Path(binary_path)
self.path = Runtime.path_from_name(self.name)
if self.name not in ("podman", "docker"):
raise errors.UnsupportedContainerRuntime(self.name)
@staticmethod
def path_from_name(name: str) -> Path:
name_path = Path(name)
if name_path.is_file():
return name_path
else:
runtime = shutil.which(name_path)
if runtime is None:
raise errors.NoContainerTechException(name)
return Path(runtime)
@staticmethod
def get_default_runtime_name() -> str:
return "podman" if platform.system() == "Linux" else "docker"

View file

@ -605,17 +605,18 @@ class WaitingWidgetContainer(WaitingWidget):
)
elif platform.system() == "Linux":
# "not_running" here means that the `podman image ls` command failed.
message = (
self.show_error(
"<strong>Dangerzone requires Podman</strong><br><br>"
"Podman is installed but cannot run properly. See errors below"
"Podman is installed but cannot run properly. See errors below",
error,
)
else:
message = (
self.show_error(
"<strong>Dangerzone requires Docker Desktop</strong><br><br>"
"Docker is installed but isn't running.<br><br>"
"Open Docker and make sure it's running in the background."
"Open Docker and make sure it's running in the background.",
error,
)
self.show_error(message, error)
else:
self.show_message(
"Installing the Dangerzone container image.<br><br>"

View file

@ -1,6 +1,7 @@
import json
import logging
import os
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict
from packaging import version
@ -42,6 +43,15 @@ class Settings:
def custom_runtime_specified(self) -> bool:
return "container_runtime" in self.settings
def set_custom_runtime(self, runtime: str, autosave: bool = False) -> Path:
from .container_utils import Runtime # Avoid circular import
container_runtime = Runtime.path_from_name(runtime)
self.settings["container_runtime"] = str(container_runtime)
if autosave:
self.save()
return container_runtime
def get(self, key: str) -> Any:
return self.settings[key]

View file

@ -49,7 +49,7 @@ def test_get_runtime_name_non_linux(mocker: MockerFixture, tmp_path: Path) -> No
assert Runtime().name == "docker"
def test_get_unsupported_runtime_name(mocker: MockerFixture, tmp_path: Path):
def test_get_unsupported_runtime_name(mocker: MockerFixture, tmp_path: Path) -> None:
mocker.patch("dangerzone.settings.get_config_dir", return_value=tmp_path)
settings = Settings()
settings.set(