diff --git a/dangerzone/gui/main_window.py b/dangerzone/gui/main_window.py index 788ad6a..da8e11e 100644 --- a/dangerzone/gui/main_window.py +++ b/dangerzone/gui/main_window.py @@ -26,12 +26,10 @@ else: from .. import errors from ..document import SAFE_EXTENSION, Document from ..isolation_provider.container import ( - Container, NoContainerTechException, NotAvailableContainerTechException, ) -from ..isolation_provider.dummy import Dummy -from ..isolation_provider.qubes import Qubes, is_qubes_native_conversion +from ..isolation_provider.qubes import is_qubes_native_conversion from ..util import format_exception, get_resource_path, get_version from .logic import Alert, CollapsibleBox, DangerzoneGui, UpdateDialog from .updater import UpdateReport @@ -197,14 +195,11 @@ class MainWindow(QtWidgets.QMainWindow): header_layout.addWidget(self.hamburger_button) header_layout.addSpacing(15) - if isinstance(self.dangerzone.isolation_provider, Container): + if self.dangerzone.isolation_provider.should_wait_install(): # Waiting widget replaces content widget while container runtime isn't available self.waiting_widget: WaitingWidget = WaitingWidgetContainer(self.dangerzone) self.waiting_widget.finished.connect(self.waiting_finished) - - elif isinstance(self.dangerzone.isolation_provider, Dummy) or isinstance( - self.dangerzone.isolation_provider, Qubes - ): + else: # Don't wait with dummy converter and on Qubes. self.waiting_widget = WaitingWidget() self.dangerzone.is_waiting_finished = True @@ -500,8 +495,7 @@ class WaitingWidgetContainer(WaitingWidget): error: Optional[str] = None try: - assert isinstance(self.dangerzone.isolation_provider, (Dummy, Container)) - self.dangerzone.isolation_provider.is_runtime_available() + self.dangerzone.isolation_provider.is_available() except NoContainerTechException as e: log.error(str(e)) state = "not_installed" diff --git a/dangerzone/isolation_provider/base.py b/dangerzone/isolation_provider/base.py index 9404cee..fd1bd6a 100644 --- a/dangerzone/isolation_provider/base.py +++ b/dangerzone/isolation_provider/base.py @@ -254,6 +254,16 @@ class IsolationProvider(ABC): ) return errors.exception_from_error_code(error_code) + @abstractmethod + def should_wait_install(self) -> bool: + """Whether this isolation provider takes a lot of time to install.""" + pass + + @abstractmethod + def is_available(self) -> bool: + """Whether the backing implementation of the isolation provider is available.""" + pass + @abstractmethod def get_max_parallel_conversions(self) -> int: pass diff --git a/dangerzone/isolation_provider/container.py b/dangerzone/isolation_provider/container.py index cfb0f0a..a35b2b9 100644 --- a/dangerzone/isolation_provider/container.py +++ b/dangerzone/isolation_provider/container.py @@ -304,7 +304,11 @@ class Container(IsolationProvider): return True @staticmethod - def is_runtime_available() -> bool: + def should_wait_install() -> bool: + return True + + @staticmethod + def is_available() -> bool: container_runtime = Container.get_runtime() runtime_name = Container.get_runtime_name() # Can we run `docker/podman image ls` without an error diff --git a/dangerzone/isolation_provider/dummy.py b/dangerzone/isolation_provider/dummy.py index b8e3b87..fac973f 100644 --- a/dangerzone/isolation_provider/dummy.py +++ b/dangerzone/isolation_provider/dummy.py @@ -40,9 +40,13 @@ class Dummy(IsolationProvider): return True @staticmethod - def is_runtime_available() -> bool: + def is_available() -> bool: return True + @staticmethod + def should_wait_install() -> bool: + return False + def start_doc_to_pixels_proc(self, document: Document) -> subprocess.Popen: cmd = [ sys.executable, diff --git a/dangerzone/isolation_provider/qubes.py b/dangerzone/isolation_provider/qubes.py index 61a7c8d..02f8002 100644 --- a/dangerzone/isolation_provider/qubes.py +++ b/dangerzone/isolation_provider/qubes.py @@ -21,6 +21,14 @@ class Qubes(IsolationProvider): def install(self) -> bool: return True + @staticmethod + def is_available() -> bool: + return True + + @staticmethod + def should_wait_install() -> bool: + return False + def get_max_parallel_conversions(self) -> int: return 1 diff --git a/tests/gui/test_main_window.py b/tests/gui/test_main_window.py index 7e96d22..f8060b0 100644 --- a/tests/gui/test_main_window.py +++ b/tests/gui/test_main_window.py @@ -512,7 +512,7 @@ def test_not_available_container_tech_exception( # Setup mock_app = mocker.MagicMock() dummy = Dummy() - fn = mocker.patch.object(dummy, "is_runtime_available") + fn = mocker.patch.object(dummy, "is_available") fn.side_effect = NotAvailableContainerTechException( "podman", "podman image ls logs" ) @@ -536,7 +536,7 @@ def test_no_container_tech_exception(qtbot: QtBot, mocker: MockerFixture) -> Non dummy = mocker.MagicMock() # Raise - dummy.is_runtime_available.side_effect = NoContainerTechException("podman") + dummy.is_available.side_effect = NoContainerTechException("podman") dz = DangerzoneGui(mock_app, dummy) widget = WaitingWidgetContainer(dz) diff --git a/tests/isolation_provider/test_container.py b/tests/isolation_provider/test_container.py index cf3f310..52b4c1e 100644 --- a/tests/isolation_provider/test_container.py +++ b/tests/isolation_provider/test_container.py @@ -27,9 +27,7 @@ def provider() -> Container: class TestContainer(IsolationProviderTest): - def test_is_runtime_available_raises( - self, provider: Container, fp: FakeProcess - ) -> None: + def test_is_available_raises(self, provider: Container, fp: FakeProcess) -> None: """ NotAvailableContainerTechException should be raised when the "podman image ls" command fails. @@ -40,18 +38,16 @@ class TestContainer(IsolationProviderTest): stderr="podman image ls logs", ) with pytest.raises(NotAvailableContainerTechException): - provider.is_runtime_available() + provider.is_available() - def test_is_runtime_available_works( - self, provider: Container, fp: FakeProcess - ) -> None: + def test_is_available_works(self, provider: Container, fp: FakeProcess) -> None: """ No exception should be raised when the "podman image ls" can return properly. """ fp.register_subprocess( [provider.get_runtime(), "image", "ls"], ) - provider.is_runtime_available() + provider.is_available() def test_install_raise_if_image_cant_be_installed( self, mocker: MockerFixture, provider: Container, fp: FakeProcess