Merge pull request #849 from mwhudson/state-management

refactor startup and state management a bit
This commit is contained in:
Michael Hudson-Doyle 2020-10-09 13:30:50 +13:00 committed by GitHub
commit f7c3f04887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 52 deletions

View File

@ -13,7 +13,9 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import logging
import os
import jsonschema
@ -43,7 +45,6 @@ class SubiquityController(BaseController):
super().__init__(app)
self.autoinstall_applied = False
self.context.set('controller', self)
self.setup_autoinstall()
def interactive(self):
return False
@ -80,9 +81,18 @@ class SubiquityController(BaseController):
def configured(self):
"""Let the world know that this controller's model is now configured.
"""
with open(self.app.state_path('states', self.name), 'w') as fp:
json.dump(self.serialize(), fp)
if self.model_name is not None:
self.app.base_model.configured(self.model_name)
def load_state(self):
state_path = self.app.state_path('states', self.name)
if not os.path.exists(state_path):
return
with open(state_path) as fp:
self.deserialize(json.load(fp))
def deserialize(self, state):
pass
@ -109,6 +119,9 @@ class RepeatedController(RepeatedController):
super().__init__(orig, index)
self.autoinstall_applied = False
def setup_autoinstall(self):
pass
async def apply_autoinstall_config(self):
await self.orig.apply_autoinstall_config(index=self.index)
@ -120,3 +133,6 @@ class RepeatedController(RepeatedController):
def make_autoinstall(self):
return {}
def load_state(self):
pass

View File

@ -257,12 +257,12 @@ class Subiquity(TuiApplication):
print(_("press enter to start a shell"))
input()
os.system("cd / && bash")
self.controllers.load("Reporting")
self.controllers.Reporting.start()
self.controllers.load("Error")
with self.context.child("core_validation", level="INFO"):
jsonschema.validate(self.autoinstall_config, self.base_schema)
self.controllers.load("Early")
self.controllers.Reporting.setup_autoinstall()
self.controllers.Early.setup_autoinstall()
self.controllers.Error.setup_autoinstall()
if self.controllers.Early.cmds:
stamp_file = self.state_path("early-commands")
if our_tty != primary_tty:
@ -326,7 +326,13 @@ class Subiquity(TuiApplication):
print()
break
def load_serialized_state(self):
for controller in self.controllers.instances:
controller.load_state()
async def start(self):
self.controllers.load_all()
self.load_serialized_state()
await self.connect()
if self.opts.autoinstall is not None:
await self.load_autoinstall_config()
@ -334,7 +340,7 @@ class Subiquity(TuiApplication):
open('/run/casper-no-prompt', 'w').close()
await super().start(start_urwid=self.interactive())
if not self.interactive():
self.select_initial_screen(0)
self.select_initial_screen()
def _exception_handler(self, loop, context):
exc = context.get('exception')
@ -346,6 +352,15 @@ class Subiquity(TuiApplication):
return
super()._exception_handler(loop, context)
def _remove_last_screen(self):
last_screen = self.state_path('last-screen')
if os.path.exists(last_screen):
os.unlink(last_screen)
def exit(self):
self._remove_last_screen()
super().exit()
def extra_urwid_loop_args(self):
return dict(input_filter=self.input_filter.filter)
@ -410,13 +425,31 @@ class Subiquity(TuiApplication):
if isinstance(self.ui.body, BaseView):
self.ui.body.remove_overlay(overlay)
def select_initial_screen(self, index):
def initial_controller_index(self):
if not self.updated:
return 0
state_path = self.state_path('last-screen')
if not os.path.exists(state_path):
return 0
with open(state_path) as fp:
last_screen = fp.read().strip()
controller_index = 0
for i, controller in enumerate(self.controllers.instances):
if controller.name == last_screen:
controller_index = i
return controller_index
def select_initial_screen(self):
self.error_reporter.load_reports()
for report in self.error_reporter.reports:
if report.kind == ErrorReportKind.UI and not report.seen:
self.show_error_report(report.ref())
break
super().select_initial_screen(index)
index = self.initial_controller_index()
for controller in self.controllers.instances[:index]:
controller.configured()
self.controllers.index = index - 1
self.next_screen()
async def move_screen(self, increment, coro):
try:
@ -453,6 +486,8 @@ class Subiquity(TuiApplication):
view = await super().make_view_for_controller(new)
if new.answers:
self.aio_loop.call_soon(new.run_answers)
with open(self.state_path('last-screen'), 'w') as fp:
fp.write(new.name)
return view
else:
if self.autoinstall_config and not new.autoinstall_applied:

View File

@ -122,17 +122,8 @@ class Application:
controller.start()
log.debug("controllers started")
def load_serialized_state(self):
for controller in self.controllers.instances:
state_path = self.state_path('states', controller.name)
if not os.path.exists(state_path):
continue
with open(state_path) as fp:
controller.deserialize(json.load(fp))
async def start(self):
self.controllers.load_all()
self.load_serialized_state()
self._connect_base_signals()
self.start_controllers()

View File

@ -16,7 +16,6 @@
import asyncio
import inspect
import logging
import os
import yaml
import urwid
@ -80,15 +79,6 @@ class TuiApplication(Application):
self.urwid_loop = None
self.cur_screen = None
def _remove_last_screen(self):
last_screen = self.state_path('last-screen')
if os.path.exists(last_screen):
os.unlink(last_screen)
def exit(self):
self._remove_last_screen()
super().exit()
def run_command_in_foreground(self, cmd, before_hook=None, after_hook=None,
**kw):
screen = self.urwid_loop.screen
@ -122,8 +112,6 @@ class TuiApplication(Application):
raise
else:
self.cur_screen = new
with open(self.state_path('last-screen'), 'w') as fp:
fp.write(new.name)
return view
async def _wait_with_indication(self, awaitable, show, hide=None):
@ -190,7 +178,6 @@ class TuiApplication(Application):
async def _move_screen(self, increment, coro):
if coro is not None:
await coro
self.save_state()
old, self.cur_screen = self.cur_screen, None
if old is not None:
old.context.exit("completed")
@ -228,12 +215,7 @@ class TuiApplication(Application):
def prev_screen(self):
self.aio_loop.create_task(self.move_screen(-1, None))
def select_initial_screen(self, controller_index):
for controller in self.controllers.instances[:controller_index]:
controller.configured()
self.controllers.index = controller_index - 1
for controller in self.controllers.instances[:controller_index]:
controller.configured()
def select_initial_screen(self):
self.next_screen()
def run_scripts(self, scripts):
@ -340,21 +322,7 @@ class TuiApplication(Application):
extend_dec_special_charmap()
self.toggle_rich()
self.urwid_loop.start()
self.select_initial_screen(self.initial_controller_index())
def initial_controller_index(self):
if not self.updated:
return 0
state_path = self.state_path('last-screen')
if not os.path.exists(state_path):
return 0
with open(state_path) as fp:
last_screen = fp.read().strip()
controller_index = 0
for i, controller in enumerate(self.controllers.instances):
if controller.name == last_screen:
controller_index = i
return controller_index
self.select_initial_screen()
async def start(self, start_urwid=True):
await super().start()