From 007dd3e5ef1c86cd56759676a021a36bbac00f84 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Wed, 16 Dec 2020 10:13:04 +1300 Subject: [PATCH] tidy up answers handling a bit and fix a race --- subiquity/client/client.py | 13 +++++++++- subiquity/client/controllers/filesystem.py | 29 ++++++++-------------- subiquitycore/controllers/network.py | 5 ++-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/subiquity/client/client.py b/subiquity/client/client.py index cb5ac283..37c31226 100644 --- a/subiquity/client/client.py +++ b/subiquity/client/client.py @@ -14,6 +14,7 @@ # along with this program. If not, see . import asyncio +import inspect import logging import os import signal @@ -403,10 +404,20 @@ class SubiquityClient(TuiApplication): log.debug("showing InstallConfirmation over %s", self.ui.body) self.add_global_overlay(InstallConfirmation(self)) + async def _start_answers_for_view(self, controller, view): + # The view returned by make_view_for_controller is not always shown + # immediately (if progress is being shown, but has not yet been shown + # for a full second) so wait until it is before starting the answers. + while self.ui.body is not view: + await asyncio.sleep(0.1) + coro = controller.run_answers() + if inspect.iscoroutine(coro): + await coro + async def make_view_for_controller(self, new): view = await super().make_view_for_controller(new) if new.answers: - self.aio_loop.call_soon(new.run_answers) + self.aio_loop.create_task(self._start_answers_for_view(new, view)) with open(self.state_path('last-screen'), 'w') as fp: fp.write(new.name) return view diff --git a/subiquity/client/controllers/filesystem.py b/subiquity/client/controllers/filesystem.py index c545462d..10420300 100644 --- a/subiquity/client/controllers/filesystem.py +++ b/subiquity/client/controllers/filesystem.py @@ -13,6 +13,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import asyncio import logging from subiquitycore.lsb_release import lsb_release @@ -82,11 +83,13 @@ class FilesystemController(SubiquityTuiController, FilesystemManipulator): self.supports_resilient_boot = release >= '20.04' if status.error_report: self.app.show_error_report(status.error_report) - if self.answers: - self.app.aio_loop.call_soon(self._start_answers) return GuidedDiskSelectionView(self) - def _start_answers(self): + async def run_answers(self): + # Wait for probing to finish. + while not isinstance(self.ui.body, GuidedDiskSelectionView): + await asyncio.sleep(0.1) + if self.answers['guided']: disk = self.model.all_disks()[self.answers['guided-index']] method = self.answers.get('guided-method') @@ -95,13 +98,12 @@ class FilesystemController(SubiquityTuiController, FilesystemManipulator): 'use_lvm': method == "lvm", } self.ui.body.done(self.ui.body.form) + await self.app.confirm_install() + self.finish() elif self.answers['manual']: self.manual() - - def run_answers(self): - # Handled above as we only want to run answers when probing - # completes. - pass + await self._run_actions(self.answers['manual']) + self.answers['manual'] = [] def _action_get(self, id): dev_spec = id[0].split() @@ -207,17 +209,6 @@ class FilesystemController(SubiquityTuiController, FilesystemManipulator): def manual(self): self.ui.set_body(FilesystemView(self.model, self)) - if self.answers['guided']: - async def t(): - await self.app.confirm_install() - self.finish() - self.app.aio_loop.create_task(t()) - if self.answers['manual']: - self.app.aio_loop.create_task(self._manual_answers()) - - async def _manual_answers(self): - await self._run_actions(self.answers['manual']) - self.answers['manual'] = [] def guided(self): self.ui.set_body(GuidedDiskSelectionView(self)) diff --git a/subiquitycore/controllers/network.py b/subiquitycore/controllers/network.py index 77f09702..8394c717 100644 --- a/subiquitycore/controllers/network.py +++ b/subiquitycore/controllers/network.py @@ -491,14 +491,13 @@ class BaseNetworkController(BaseController): class NetworkAnswersMixin: - def run_answers(self): + async def run_answers(self): if self.answers.get('accept-default', False): self.done() elif self.answers.get('actions', False): actions = self.answers['actions'] self.answers.clear() - self.app.aio_loop.create_task( - self._run_actions(actions)) + await self._run_actions(actions) def _action_get(self, id): dev_spec = id[0].split()