Add a way to cancel an ongoing container upgrade

This might happen if people in a hurry want to do a conversion without
having to wait for the new container to be ready.
This commit is contained in:
Alexis Métaireau 2025-04-30 19:32:30 +02:00
parent 27aa2b05a1
commit e9ddf8b375
No known key found for this signature in database
GPG key ID: C65C7A89A8FFC56E
3 changed files with 57 additions and 21 deletions

View file

@ -462,7 +462,9 @@ class InstallContainerThread(QtCore.QThread):
def run(self) -> None:
error = None
try:
should_upgrade = bool(self.dangerzone.settings.get("updater_check_all"))
should_upgrade = bool(
self.dangerzone.settings.get("updater_container_needs_update")
)
installed = self.dangerzone.isolation_provider.install(
should_upgrade=should_upgrade, callback=self.process_stdout.emit
)
@ -526,6 +528,26 @@ class WaitingWidgetContainer(WaitingWidget):
# Linux states
# - "install_container"
def _create_button(
self, label: str, event: QtCore.Signal, hide: bool = False
) -> QtWidgets.QWidget:
button = QtWidgets.QPushButton(label)
button.clicked.connect(event)
buttons_layout = QtWidgets.QHBoxLayout()
buttons_layout.addStretch()
buttons_layout.addWidget(button)
buttons_layout.addStretch()
widget = QtWidgets.QWidget()
widget.setLayout(buttons_layout)
if hide:
widget.hide()
return widget
def _hide_buttons(self) -> None:
self.button_check.hide()
self.button_cancel.hide()
def __init__(self, dangerzone: DangerzoneGui) -> None:
super(WaitingWidgetContainer, self).__init__()
self.dangerzone = dangerzone
@ -537,14 +559,10 @@ class WaitingWidgetContainer(WaitingWidget):
self.label.setStyleSheet("QLabel { font-size: 20px; }")
# Buttons
check_button = QtWidgets.QPushButton("Check Again")
check_button.clicked.connect(self.check_state)
buttons_layout = QtWidgets.QHBoxLayout()
buttons_layout.addStretch()
buttons_layout.addWidget(check_button)
buttons_layout.addStretch()
self.buttons = QtWidgets.QWidget()
self.buttons.setLayout(buttons_layout)
self.button_check = self._create_button("Check Again", self.check_state)
self.button_cancel = self._create_button(
"Cancel", self.cancel_install, hide=True
)
self.traceback = TracebackWidget()
@ -554,7 +572,8 @@ class WaitingWidgetContainer(WaitingWidget):
layout.addWidget(self.label)
layout.addWidget(self.traceback)
layout.addStretch()
layout.addWidget(self.buttons)
layout.addWidget(self.button_check)
layout.addWidget(self.button_cancel)
layout.addStretch()
self.setLayout(layout)
@ -584,18 +603,22 @@ class WaitingWidgetContainer(WaitingWidget):
# Update the state
self.state_change(state, error)
def cancel_install(self) -> None:
self.install_container_t.terminate()
self.finished.emit()
def show_error(self, msg: str, details: Optional[str] = None) -> None:
self.label.setText(msg)
show_traceback = details is not None
if show_traceback:
self.traceback.set_content(details)
self.traceback.setVisible(show_traceback)
self.buttons.show()
self.button_check.show()
def show_message(self, msg: str) -> None:
self.label.setText(msg)
self.traceback.setVisible(False)
self.buttons.hide()
self._hide_buttons()
def installation_finished(self, error: Optional[str] = None) -> None:
if error:
@ -649,11 +672,23 @@ class WaitingWidgetContainer(WaitingWidget):
error,
)
else:
self.show_message(
"Installing the Dangerzone container image.<br><br>"
"This might take a few minutes..."
needs_update = bool(
self.dangerzone.settings.get("updater_container_needs_update")
)
if needs_update:
message = (
"Downloading and upgrading the Dangerzone container image.<br><br>"
"This might take a few minutes..."
)
else:
message = (
"Installing the Dangerzone container image.<br><br>"
"This might take a few minutes..."
)
self.show_message(message)
self.traceback.setVisible(True)
self.button_cancel.show()
self.button_check.hide()
self.install_container_t = InstallContainerThread(self.dangerzone)
self.install_container_t.finished.connect(self.installation_finished)

View file

@ -169,8 +169,9 @@ def check_for_updates(settings: Settings) -> UpdaterReport:
slightly different answer:
1. No new updates: Return an empty update report.
2. Updates are available: Return an update report with the latest version and
changelog, in HTML format.
2. Updates are available:
Return an update report with the latest version and changelog, or with the
information the container image needs to be updated.
3. Update check failed: Return an update report that holds just the error
message.
"""
@ -215,9 +216,7 @@ def check_for_updates(settings: Settings) -> UpdaterReport:
report.changelog = gh_changelog
container_name = container_utils.expected_image_name()
container_needs_update, _ = is_container_update_available(
container_name, DEFAULT_PUBKEY_LOCATION
)
container_needs_update, _ = is_container_update_available(container_name)
report.container_needs_update = container_needs_update
settings.set(

View file

@ -133,7 +133,9 @@ class Signature:
return full_digest.replace("sha256:", "")
def is_update_available(image_str: str, pubkey: Path) -> Tuple[bool, Optional[str]]:
def is_update_available(
image_str: str, pubkey: Path = DEFAULT_PUBKEY_LOCATION
) -> Tuple[bool, Optional[str]]:
"""
Check if a new image is available, doing all the necessary checks ensuring it
would be safe to upgrade.