From 414a2235e688ca62ba04a279816c0facce469338 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Tue, 12 Apr 2022 20:39:22 +0200 Subject: [PATCH] storage: fix screen sometimes not refreshing after slow probing When we reach the storage screens on the installer, if the devices probing operation has not finished, we: * display a temporary "Probing" screen. * create an asynchronous task (a.k.a., probing task) that will eventually show the "Guide Storage" screen when the probing operation finishes. The probing task checks, when it finishes, that the screen currently visible is the "Probing" screen. This is the expectation and is true in most scenarios. But in case a different screen is visible, we skip refreshing the display. Unfortunately, sometimes, a "Progress" screen is shown for some time before the "Probing" screen appears. Consequently, we do not refresh the screen if the probing operation finishes whilst the Progress screen is visible. In order to keep the view returned by make_ui() up-to-date and make sure that the right screen is shown even if the probing operation finishes early, we use the level indirection that was implemented in make_ui. https://bugs.launchpad.net/subiquity/+bug/1968161 Signed-off-by: Olivier Gayot --- subiquity/client/controllers/filesystem.py | 25 ++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/subiquity/client/controllers/filesystem.py b/subiquity/client/controllers/filesystem.py index 5ec56c3b..5fb9a400 100644 --- a/subiquity/client/controllers/filesystem.py +++ b/subiquity/client/controllers/filesystem.py @@ -15,8 +15,10 @@ import asyncio import logging +from typing import Callable, Optional from subiquitycore.lsb_release import lsb_release +from subiquitycore.view import BaseView from subiquity.client.controller import SubiquityTuiController from subiquity.common.filesystem import gaps @@ -50,19 +52,34 @@ class FilesystemController(SubiquityTuiController, FilesystemManipulator): self.answers.setdefault('guided', False) self.answers.setdefault('guided-index', 0) self.answers.setdefault('manual', []) + self.current_view: Optional[BaseView] = None + + async def make_ui(self) -> Callable[[], BaseView]: + def get_current_view() -> BaseView: + assert self.current_view is not None + return self.current_view - async def make_ui(self): status = await self.endpoint.guided.GET() if status.status == ProbeStatus.PROBING: self.app.aio_loop.create_task(self._wait_for_probing()) - return SlowProbing(self) + self.current_view = SlowProbing(self) else: - return self.make_guided_ui(status) + self.current_view = self.make_guided_ui(status) + # NOTE: If we return a BaseView instance directly here, we have no + # guarantee that it will be displayed on the screen by the time the + # probing operation finishes. Therefore, to allow us to reliably + # replace the screen by the "Guided Storage" when the probing operation + # finishes, we add a level of indirection. + # In essence, this allows us to make modifications to the screen + # that eventually will be displayed. + # This is mostly a workaround for the issue described in LP #1968161 + return get_current_view async def _wait_for_probing(self): status = await self.endpoint.guided.GET(wait=True) + self.current_view = self.make_guided_ui(status) if isinstance(self.ui.body, SlowProbing): - self.ui.set_body(self.make_guided_ui(status)) + self.ui.set_body(self.current_view) else: log.debug("not refreshing the display. Current display is %r", self.ui.body)