Show a progress bar when installing new container images
Right now, the way we integrate with container engines (e.g. Podman, Docker) is via a command-line interface, which gives us little margin for some operations.
For instance, when downloading a new image with podman pull image-name the way we have to track progress is via the command line, which is hard to leverage in a different way, if for instance we were to display a progress bar to the users instead, which would be a lot more UX-friendly.
We might want to have different "backends" for the container runtime, and the podman one could be done via podman-py, which provides way to handle this, like this (with Qt added):
from podman import PodmanClient
from dangerzone.container_utils import expected_image_name
from PySide6 import QtCore, QtGui, QtSvg, QtWidgets
class Window(QtWidgets.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.progress = QtWidgets.QProgressBar(self)
self.progress.setGeometry(200, 80, 250, 20)
self.btn = QtWidgets.QPushButton("Download", self)
self.btn.move(200, 120)
self.btn.clicked.connect(self.download)
self.show()
def download(self):
uri = "unix:///run/user/1000/podman/podman.sock"
with PodmanClient(base_url=uri) as client:
stream = client.images.pull(
expected_image_name(),
stream=True, # enables streaming
decode=True # convert each chunk into a python dict
)
for chunk in stream:
if chunk.get("status") == "Downloading":
current = chunk.get("progressDetail")["current"]
total = chunk.get("progressDetail")["total"]
self.progress.setValue((current / total) * 100)
A PR has been opened by @apyrgio upstream and we're waiting on their feedback. See https://github.com/containers/podman-py/pull/558 for more details.
We had a discussion with Alexis on the subject of progress bars, as we're getting ready for the 0.10.0 release, and I want to capture our understanding in this issue, because the subject is kinda tricky.
First of all, we have tried to sidestep this issue, by capturing the output of every command we spawn, including podman load and podman pull (see https://github.com/freedomofpress/dangerzone/issues/1236). We aimed to at least get an indication from podman load / podman pull that would show to the users that something is in progress, but unfortunately, there's no such output from Podman, at least on macOS (see https://github.com/containers/podman/issues/15714), no matter how dirty we wanted to play (e.g., parse somehow the progress messages with the ANSI escape codes).
If we want to give to the users something working, we have to go through the Podman HTTP API. That's where the podman-py PR comes into play, because it introduces a Python interface over podman system service. The good thing is that - in theory - every missing piece is in place:
- [x] A Pythonic way to spawn, wait, and stop
podman system service(will be merged as part of https://github.com/freedomofpress/dangerzone/pull/1225) - [x] Working code that can make use of the Podman HTTP API (see https://github.com/freedomofpress/dangerzone/issues/1164#issue-3097640889)
In practice though, we're blocked on something important, that the Python bindings for Podman do not work out of the box on Windows (see https://github.com/containers/podman-py/issues/554). Solving this requires some development work on the podman-py codebase, which ideally I wanted to do after 0.10.0.
In conclusion, if we want to release Dangerzone in time, we have to punt this for later, and show a message to our users that the load / pull operation will take a while. Hopefully we can tackle it in a subsequent release properly.