change controller api to return a view, rather than setting it

This commit is contained in:
Michael Hudson-Doyle 2020-09-18 11:44:00 +12:00
parent eb5dba579e
commit f0082c2068
21 changed files with 78 additions and 86 deletions

View File

@ -47,7 +47,7 @@ class RecoveryChooserController(RecoveryChooserBaseController):
# one of the current views # one of the current views
self._current_view = None self._current_view = None
def start_ui(self): def make_ui(self):
# current view is preserved, so going back comes back to the right # current view is preserved, so going back comes back to the right
# screen # screen
if self._current_view is None: if self._current_view is None:
@ -57,7 +57,7 @@ class RecoveryChooserController(RecoveryChooserBaseController):
if self._model_view is not None: if self._model_view is not None:
self._current_view = self._model_view self._current_view = self._model_view
self.ui.set_body(self._current_view) return self._current_view
def _make_views(self): def _make_views(self):
current_view = None current_view = None
@ -89,9 +89,8 @@ class RecoveryChooserController(RecoveryChooserBaseController):
class RecoveryChooserConfirmController(RecoveryChooserBaseController): class RecoveryChooserConfirmController(RecoveryChooserBaseController):
def start_ui(self): def make_ui(self):
view = ChooserConfirmView(self, self.model.selection) return ChooserConfirmView(self, self.model.selection)
self.ui.set_body(view)
def confirm(self): def confirm(self):
log.warning("user action %s", self.model.selection) log.warning("user action %s", self.model.selection)

View File

@ -147,8 +147,7 @@ class IdentityController(TuiController):
super().__init__(app) super().__init__(app)
self.model = app.base_model.identity self.model = app.base_model.identity
def start_ui(self): def make_ui(self):
self.ui.set_body(IdentityView(self.model, self))
if get_managed(): if get_managed():
device_owner = get_device_owner() device_owner = get_device_owner()
if device_owner: if device_owner:
@ -158,7 +157,9 @@ class IdentityController(TuiController):
cp = run_command(['ssh-keygen', '-lf', key_file]) cp = run_command(['ssh-keygen', '-lf', key_file])
self.model.user.fingerprints = ( self.model.user.fingerprints = (
cp.stdout.replace('\r', '').splitlines()) cp.stdout.replace('\r', '').splitlines())
self.login() return self.make_login_view()
else:
return IdentityView(self.model, self)
def identity_done(self, email): def identity_done(self, email):
if self.opts.dry_run: if self.opts.dry_run:
@ -199,7 +200,7 @@ class IdentityController(TuiController):
if self.model.user is None: if self.model.user is None:
self.app.prev_screen() self.app.prev_screen()
def login(self): def make_login_view(self):
title = "Configuration Complete" title = "Configuration Complete"
self.ui.set_header(title) self.ui.set_header(title)
@ -208,7 +209,8 @@ class IdentityController(TuiController):
login_view = LoginView(self.opts, self.model, self, ifaces) login_view = LoginView(self.opts, self.model, self, ifaces)
login_view._w.focus_position = 2 login_view._w.focus_position = 2
self.ui.set_body(login_view) def login(self):
self.ui.set_body(self.make_login_view())
def login_done(self): def login_done(self):
if not self.opts.dry_run: if not self.opts.dry_run:

View File

@ -120,7 +120,7 @@ class TestChooserConfirmController(unittest.TestCase):
c = RecoveryChooserConfirmController(app) c = RecoveryChooserConfirmController(app)
c.model = make_model() c.model = make_model()
c.model.select(c.model.systems[0], c.model.systems[0].actions[0]) c.model.select(c.model.systems[0], c.model.systems[0].actions[0])
c.start_ui() c.make_ui()
ccv.assert_called() ccv.assert_called()
@ -146,13 +146,12 @@ class TestChooserController(unittest.TestCase):
def test_current_ui_first(self, cv, ccsv): def test_current_ui_first(self, cv, ccsv):
app = make_app(model=make_model()) app = make_app(model=make_model())
c = RecoveryChooserController(app) c = RecoveryChooserController(app)
c.ui.start_ui = mock.Mock()
# current system view is constructed # current system view is constructed
ccsv.assert_called_with(c, c.model.current, has_more=True) ccsv.assert_called_with(c, c.model.current, has_more=True)
# as well as all systems view # as well as all systems view
cv.assert_called_with(c, c.model.systems) cv.assert_called_with(c, c.model.systems)
c.start_ui() v = c.make_ui()
c.ui.set_body.assert_called_with('current') self.assertEqual(v, 'current')
# user selects more options and the view is replaced # user selects more options and the view is replaced
c.more_options() c.more_options()
c.ui.set_body.assert_called_with('all') c.ui.set_body.assert_called_with('all')
@ -164,13 +163,12 @@ class TestChooserController(unittest.TestCase):
def test_current_current_all_there_and_back(self, cv, ccsv): def test_current_current_all_there_and_back(self, cv, ccsv):
app = make_app(model=make_model()) app = make_app(model=make_model())
c = RecoveryChooserController(app) c = RecoveryChooserController(app)
c.ui.start_ui = mock.Mock()
# sanity # sanity
ccsv.assert_called_with(c, c.model.current, has_more=True) ccsv.assert_called_with(c, c.model.current, has_more=True)
cv.assert_called_with(c, c.model.systems) cv.assert_called_with(c, c.model.systems)
c.start_ui() v = c.make_ui()
c.ui.set_body.assert_called_with('current') self.assertEqual(v, 'current')
# user selects more options and the view is replaced # user selects more options and the view is replaced
c.more_options() c.more_options()
c.ui.set_body.assert_called_with('all') c.ui.set_body.assert_called_with('all')
@ -189,13 +187,12 @@ class TestChooserController(unittest.TestCase):
model = RecoverySystemsModel.from_systems([model2_current]) model = RecoverySystemsModel.from_systems([model2_current])
app = make_app(model=model) app = make_app(model=model)
c = RecoveryChooserController(app) c = RecoveryChooserController(app)
c.ui.start_ui = mock.Mock()
# both views are constructed # both views are constructed
ccsv.assert_called_with(c, c.model.current, has_more=False) ccsv.assert_called_with(c, c.model.current, has_more=False)
cv.assert_called_with(c, c.model.systems) cv.assert_called_with(c, c.model.systems)
c.start_ui() v = c.make_ui()
c.ui.set_body.assert_called_with('current') self.assertEqual(v, 'current')
# going back does nothing # going back does nothing
c.back() c.back()
c.ui.set_body.not_called() c.ui.set_body.not_called()
@ -208,7 +205,6 @@ class TestChooserController(unittest.TestCase):
model = RecoverySystemsModel.from_systems([model1_non_current]) model = RecoverySystemsModel.from_systems([model1_non_current])
app = make_app(model=model) app = make_app(model=model)
c = RecoveryChooserController(app) c = RecoveryChooserController(app)
c.ui.start_ui = mock.Mock()
# sanity # sanity
self.assertIsNone(c.model.current) self.assertIsNone(c.model.current)
@ -218,5 +214,5 @@ class TestChooserController(unittest.TestCase):
# current system view is not constructed at all # current system view is not constructed at all
ccsv.assert_not_called() ccsv.assert_not_called()
c.start_ui() v = c.make_ui()
c.ui.set_body.assert_called_with('all') self.assertEqual(v, 'all')

View File

@ -22,9 +22,8 @@ class WelcomeController(TuiController):
welcome_view = WelcomeView welcome_view = WelcomeView
def start_ui(self): def make_ui(self):
view = self.welcome_view(self) return self.welcome_view(self)
self.ui.set_body(view)
def done(self): def done(self):
self.app.next_screen() self.app.next_screen()

View File

@ -222,15 +222,17 @@ class FilesystemController(SubiquityTuiController):
await self._start_task await self._start_task
await self._probe_task.wait() await self._probe_task.wait()
if isinstance(self.ui.body, SlowProbing): if isinstance(self.ui.body, SlowProbing):
self.start_ui() self.ui.set_body(self.make_ui())
def start_ui(self): def make_ui(self):
if self._probe_task.task is None or not self._probe_task.task.done(): if self._probe_task.task is None or not self._probe_task.task.done():
self.ui.set_body(SlowProbing(self))
schedule_task(self._wait_for_probing()) schedule_task(self._wait_for_probing())
return SlowProbing(self)
elif True in self._crash_reports: elif True in self._crash_reports:
self.ui.set_body(ProbingFailed(self)) pr = self._crash_reports[True]
self.ui.body.show_error() if pr is not None:
self.app.show_error_report(pr)
return ProbingFailed(self)
else: else:
# Once we've shown the filesystem UI, we stop listening for udev # Once we've shown the filesystem UI, we stop listening for udev
# events as merging system changes with configuration the user has # events as merging system changes with configuration the user has
@ -238,20 +240,24 @@ class FilesystemController(SubiquityTuiController):
# not today. # not today.
self.convert_autoinstall_config() self.convert_autoinstall_config()
self.stop_listening_udev() self.stop_listening_udev()
self.ui.set_body(GuidedDiskSelectionView(self))
pr = self._crash_reports.get(False) pr = self._crash_reports.get(False)
if pr is not None: if pr is not None:
self.app.show_error_report(pr) self.app.show_error_report(pr)
if self.answers['guided']: if self.answers:
disk = self.model.all_disks()[self.answers['guided-index']] self.app.aio_loop.call_soon(self._start_answers)
method = self.answers.get('guided-method') return GuidedDiskSelectionView(self)
self.ui.body.form.guided_choice.value = {
'disk': disk, def _start_answers(self):
'use_lvm': method == "lvm", if self.answers['guided']:
} disk = self.model.all_disks()[self.answers['guided-index']]
self.ui.body.done(self.ui.body.form) method = self.answers.get('guided-method')
elif self.answers['manual']: self.ui.body.form.guided_choice.value = {
self.manual() 'disk': disk,
'use_lvm': method == "lvm",
}
self.ui.body.done(self.ui.body.form)
elif self.answers['manual']:
self.manual()
def run_answers(self): def run_answers(self):
# Handled above as we only want to run answers when probing # Handled above as we only want to run answers when probing
@ -366,14 +372,8 @@ class FilesystemController(SubiquityTuiController):
self._run_iterator(self._run_actions(self.answers['manual'])) self._run_iterator(self._run_actions(self.answers['manual']))
self.answers['manual'] = [] self.answers['manual'] = []
def guided(self, method): def guided(self):
v = GuidedDiskSelectionView(self.model, self, method) self.ui.set_body(GuidedDiskSelectionView(self))
self.ui.set_body(v)
if self.answers['guided']:
index = self.answers['guided-index']
v.form.guided.value = True
v.form.guided_choice.disk.widget.index = index
v.form._emit('done')
def reset(self): def reset(self):
log.info("Resetting Filesystem model") log.info("Resetting Filesystem model")

View File

@ -50,8 +50,8 @@ class IdentityController(SubiquityTuiController):
if 'user-data' not in self.app.autoinstall_config: if 'user-data' not in self.app.autoinstall_config:
raise Exception("no identity data provided") raise Exception("no identity data provided")
def start_ui(self): def make_ui(self):
self.ui.set_body(IdentityView(self.model, self)) return IdentityView(self.model, self)
def run_answers(self): def run_answers(self):
if all(elem in self.answers for elem in if all(elem in self.answers for elem in

View File

@ -152,7 +152,7 @@ class InstallProgressController(SubiquityTuiController):
self.progress_view.finish_all() self.progress_view.finish_all()
self.progress_view.set_status(('info_error', self.progress_view.set_status(('info_error',
_("An error has occurred"))) _("An error has occurred")))
self.start_ui() self.ui.set_body(self.make_ui())
if crash_report is not None: if crash_report is not None:
self.progress_view.show_error(crash_report) self.progress_view.show_error(crash_report)
@ -440,7 +440,7 @@ class InstallProgressController(SubiquityTuiController):
def click_reboot(self): def click_reboot(self):
schedule_task(self._click_reboot()) schedule_task(self._click_reboot())
def start_ui(self): def make_ui(self):
if self.install_state in [ if self.install_state in [
InstallState.NOT_STARTED, InstallState.NOT_STARTED,
InstallState.RUNNING, InstallState.RUNNING,
@ -451,8 +451,8 @@ class InstallProgressController(SubiquityTuiController):
elif self.install_state == InstallState.ERROR: elif self.install_state == InstallState.ERROR:
self.progress_view.title = ( self.progress_view.title = (
_('An error occurred during installation')) _('An error occurred during installation'))
self.ui.set_body(self.progress_view)
schedule_task(self.move_on()) schedule_task(self.move_on())
return self.progress_view
def run_answers(self): def run_answers(self):
pass pass

View File

@ -61,11 +61,10 @@ class KeyboardController(SubiquityTuiController):
log.debug("loading launguage %s", code) log.debug("loading launguage %s", code)
self.model.load_language(code) self.model.load_language(code)
def start_ui(self): def make_ui(self):
if self.model.current_lang is None: if self.model.current_lang is None:
self.model.load_language('C') self.model.load_language('C')
view = KeyboardView(self.model, self, self.opts) return KeyboardView(self.model, self, self.opts)
self.ui.set_body(view)
def run_answers(self): def run_answers(self):
if 'layout' in self.answers: if 'layout' in self.answers:

View File

@ -122,9 +122,9 @@ class MirrorController(SubiquityTuiController):
self.check_state = CheckState.DONE self.check_state = CheckState.DONE
self.model.set_country(cc) self.model.set_country(cc)
def start_ui(self): def make_ui(self):
self.check_state = CheckState.DONE self.check_state = CheckState.DONE
self.ui.set_body(MirrorView(self.model, self)) return MirrorView(self.model, self)
def run_answers(self): def run_answers(self):
if 'mirror' in self.answers: if 'mirror' in self.answers:

View File

@ -48,8 +48,8 @@ class ProxyController(SubiquityTuiController):
# by everything; don't have a way to do that today. # by everything; don't have a way to do that today.
pass pass
def start_ui(self): def make_ui(self):
self.ui.set_body(ProxyView(self.model, self)) return ProxyView(self.model, self)
def run_answers(self): def run_answers(self):
if 'proxy' in self.answers: if 'proxy' in self.answers:

View File

@ -74,8 +74,9 @@ class RebootController(SubiquityTuiController):
await self.app.controllers.InstallProgress.reboot_clicked.wait() await self.app.controllers.InstallProgress.reboot_clicked.wait()
self.reboot() self.reboot()
def start_ui(self): def make_ui(self):
schedule_task(self._run()) schedule_task(self._run())
return self.ui.body
def cancel(self): def cancel(self):
pass pass

View File

@ -222,7 +222,7 @@ class RefreshController(SubiquityTuiController):
result = await self.app.snapd.get('v2/changes/{}'.format(change)) result = await self.app.snapd.get('v2/changes/{}'.format(change))
return result['result'] return result['result']
def start_ui(self, index=1): def make_ui(self, index=1):
from subiquity.ui.views.refresh import RefreshView from subiquity.ui.views.refresh import RefreshView
if self.app.updated: if self.app.updated:
raise Skip() raise Skip()
@ -239,7 +239,7 @@ class RefreshController(SubiquityTuiController):
else: else:
raise AssertionError("unexpected index {}".format(index)) raise AssertionError("unexpected index {}".format(index))
if show: if show:
self.ui.set_body(RefreshView(self)) return RefreshView(self)
else: else:
raise Skip() raise Skip()

View File

@ -155,13 +155,13 @@ class SnapListController(SubiquityTuiController):
self.loader = self._make_loader() self.loader = self._make_loader()
self.loader.start() self.loader.start()
def start_ui(self): def make_ui(self):
if self.loader.failed or not self.app.base_model.network.has_network: if self.loader.failed or not self.app.base_model.network.has_network:
# If loading snaps failed or the network is disabled, skip the # If loading snaps failed or the network is disabled, skip the
# screen. # screen.
self.configured() self.configured()
raise Skip() raise Skip()
self.ui.set_body(SnapListView(self.model, self)) return SnapListView(self.model, self)
def run_answers(self): def run_answers(self):
if 'snaps' in self.answers: if 'snaps' in self.answers:

View File

@ -65,8 +65,8 @@ class SSHController(SubiquityTuiController):
self.model.pwauth = data.get( self.model.pwauth = data.get(
'allow-pw', not self.model.authorized_keys) 'allow-pw', not self.model.authorized_keys)
def start_ui(self): def make_ui(self):
self.ui.set_body(SSHView(self.model, self)) return SSHView(self.model, self)
def run_answers(self): def run_answers(self):
if 'ssh-import-id' in self.answers: if 'ssh-import-id' in self.answers:

View File

@ -48,9 +48,8 @@ class WelcomeController(SubiquityTuiController):
else: else:
self.model.selected_language = lang self.model.selected_language = lang
def start_ui(self): def make_ui(self):
view = WelcomeView(self.model, self) return WelcomeView(self.model, self)
self.ui.set_body(view)
def run_answers(self): def run_answers(self):
if 'lang' in self.answers: if 'lang' in self.answers:

View File

@ -644,7 +644,7 @@ class ZdevController(SubiquityTuiController):
zdevinfos = [ZdevInfo.from_row(row) for row in devices] zdevinfos = [ZdevInfo.from_row(row) for row in devices]
self.zdevinfos = OrderedDict([(i.id, i) for i in zdevinfos]) self.zdevinfos = OrderedDict([(i.id, i) for i in zdevinfos])
def start_ui(self): def make_ui(self):
self.ui.set_body(ZdevView(self)) self.ui.set_body(ZdevView(self))
def run_answers(self): def run_answers(self):

View File

@ -535,7 +535,7 @@ class FilesystemView(BaseView):
self.show_stretchy_overlay(VolGroupStretchy(self)) self.show_stretchy_overlay(VolGroupStretchy(self))
def cancel(self, button=None): def cancel(self, button=None):
self.controller.start_ui() self.controller.guided()
def reset(self, button): def reset(self, button):
self.controller.reset() self.controller.reset()

View File

@ -449,7 +449,7 @@ class NetworkController(TuiController):
dev.set_dhcp_state(v, DHCPState.TIMED_OUT) dev.set_dhcp_state(v, DHCPState.TIMED_OUT)
self.network_event_receiver.update_link(dev.ifindex) self.network_event_receiver.update_link(dev.ifindex)
def start_ui(self): def make_ui(self):
if not self.view_shown: if not self.view_shown:
self.update_initial_configs() self.update_initial_configs()
netdev_infos = [ netdev_infos = [
@ -461,7 +461,7 @@ class NetworkController(TuiController):
self.view_shown = True self.view_shown = True
self.view.update_default_routes( self.view.update_default_routes(
self.network_event_receiver.default_routes) self.network_event_receiver.default_routes)
self.ui.set_body(self.view) return self.view
def end_ui(self): def end_ui(self):
self.view = None self.view = None

View File

@ -41,7 +41,7 @@ class Application:
# "InstallProgress", # "InstallProgress",
# ] # ]
# The 'next_screen' and 'prev_screen' methods move through the list of # The 'next_screen' and 'prev_screen' methods move through the list of
# controllers in order, calling the start_ui method on the controller # controllers in order, calling the make_ui method on the controller
# instance. # instance.
def __init__(self, opts): def __init__(self, opts):

View File

@ -101,7 +101,7 @@ class TuiApplication(Application):
if self.opts.screens and new.name not in self.opts.screens: if self.opts.screens and new.name not in self.opts.screens:
raise Skip raise Skip
try: try:
new.start_ui() self.ui.set_body(new.make_ui())
self.cur_screen = new self.cur_screen = new
except Skip: except Skip:
new.context.exit("(skipped)") new.context.exit("(skipped)")

View File

@ -22,7 +22,7 @@ log = logging.getLogger("subiquitycore.tuicontroller")
class Skip(Exception): class Skip(Exception):
"""Raise this from a controller's start_ui method to skip a screen.""" """Raise this from a controller's make_ui method to skip a screen."""
class TuiController(BaseController): class TuiController(BaseController):
@ -45,11 +45,8 @@ class TuiController(BaseController):
return inst is self return inst is self
@abstractmethod @abstractmethod
def start_ui(self): def make_ui(self):
"""Start running this controller's UI. """Return the view for this controller's UI."""
This method should call self.ui.set_body.
"""
def end_ui(self): def end_ui(self):
"""Stop running this controller's UI. """Stop running this controller's UI.
@ -109,8 +106,8 @@ class RepeatedController(BaseController):
def register_signals(self): def register_signals(self):
pass pass
def start_ui(self): def make_ui(self):
self.orig.start_ui(self.index) return self.orig.make_ui(self.index)
def run_answers(self): def run_answers(self):
self.orig.run_answers() self.orig.run_answers()