Update install progress controller
Provide streaming updates to the UI during non blocking commands. For the progress controller specifically this is the output from curtin_wrap and subsequent curtin execs. Signed-off-by: Adam Stokes <adam.stokes@ubuntu.com>
This commit is contained in:
parent
57347582db
commit
709ae2a51a
|
@ -14,7 +14,9 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
from tornado.gen import coroutine
|
||||
import subiquity.utils as utils
|
||||
from subiquity.models import InstallProgressModel
|
||||
from subiquity.ui.views import ProgressView, ProgressOutput
|
||||
from subiquity.controller import ControllerPolicy
|
||||
|
||||
|
@ -22,9 +24,39 @@ log = logging.getLogger("subiquity.controller.installprogress")
|
|||
|
||||
|
||||
class InstallProgressController(ControllerPolicy):
|
||||
def __init__(self, ui, signal):
|
||||
def __init__(self, ui, signal, opts):
|
||||
self.ui = ui
|
||||
self.signal = signal
|
||||
self.opts = opts
|
||||
self.model = InstallProgressModel()
|
||||
self.progress_output_w = ProgressOutput(
|
||||
self.signal,
|
||||
"Waiting...")
|
||||
|
||||
def exit_cb(self, ret):
|
||||
log.debug("Exit: {}".format(ret))
|
||||
|
||||
@coroutine
|
||||
def run_curtin(self):
|
||||
try:
|
||||
yield utils.run_command_async(
|
||||
"/usr/local/bin/curtin_wrap.sh",
|
||||
self.install_progress_status)
|
||||
except Exception as e:
|
||||
# TODO: Implement an Error View/Controller for displaying
|
||||
# exceptions rather than kicking out of installer.
|
||||
log.error("Problem running curtin_wrap: {}".format(e))
|
||||
|
||||
@coroutine
|
||||
def run_test_curtin(self):
|
||||
""" testing streaming output
|
||||
"""
|
||||
self.install_progress_status("Starting run")
|
||||
yield utils.run_command_async(
|
||||
"cat /var/log/syslog",
|
||||
self.install_progress_status)
|
||||
log.debug("done")
|
||||
return
|
||||
|
||||
def install_progress(self):
|
||||
title = ("Installing system")
|
||||
|
@ -33,6 +65,7 @@ class InstallProgressController(ControllerPolicy):
|
|||
footer = ("Thank you for using Ubuntu!")
|
||||
self.ui.set_header(title, excerpt)
|
||||
self.ui.set_footer(footer)
|
||||
self.ui.set_body(ProgressView(self.signal, self.progress_output_w))
|
||||
if self.opts.dry_run:
|
||||
log.debug("Filesystem: this is a dry-run")
|
||||
banner = [
|
||||
|
@ -43,15 +76,14 @@ class InstallProgressController(ControllerPolicy):
|
|||
"",
|
||||
"Press (Q) to Quit."
|
||||
]
|
||||
self.progress_output_w = ProgressOutput("\n".join(banner))
|
||||
self.install_progress_status("\n".join(banner))
|
||||
# XXX: Test routine to verify the callback streaming
|
||||
# self.run_test_curtin()
|
||||
else:
|
||||
log.debug("filesystem: this is the *real* thing")
|
||||
subprocess.Popen(["/usr/local/bin/curtin_wrap.sh"],
|
||||
stdout=self.install_progress_fd,
|
||||
bufsize=1,
|
||||
universal_newlines=True)
|
||||
self.progress_output_w = ProgressOutput("Wait for it...\n\n")
|
||||
self.ui.set_body(ProgressView(self.signal, self.progress_output_w))
|
||||
self.run_curtin()
|
||||
|
||||
def install_progress_status(self, data):
|
||||
log.debug("Running status output: {}".format(data))
|
||||
self.progress_output_w.set_text(data)
|
||||
self.signal.emit_signal('refresh')
|
||||
|
|
|
@ -47,7 +47,8 @@ class Controller:
|
|||
"network": NetworkController(self.ui, self.signal),
|
||||
"filesystem": FilesystemController(self.ui, self.signal),
|
||||
"identity": IdentityController(self.ui, self.signal),
|
||||
"progress": InstallProgressController(self.ui, self.signal),
|
||||
"progress": InstallProgressController(self.ui, self.signal,
|
||||
self.opts)
|
||||
}
|
||||
self._connect_base_signals()
|
||||
|
||||
|
@ -58,6 +59,7 @@ class Controller:
|
|||
|
||||
# Add quit signal
|
||||
signals.append(('quit', self.exit))
|
||||
signals.append(('refresh', self.redraw_screen))
|
||||
self.signal.connect_signals(signals)
|
||||
|
||||
# Registers signals from each controller
|
||||
|
|
|
@ -13,8 +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/>.
|
||||
|
||||
from .filesystem import FilesystemModel
|
||||
from .installpath import InstallpathModel
|
||||
from .network import NetworkModel
|
||||
from .welcome import WelcomeModel
|
||||
from .identity import IdentityModel
|
||||
from .filesystem import FilesystemModel # NOQA
|
||||
from .installpath import InstallpathModel # NOQA
|
||||
from .network import NetworkModel # NOQA
|
||||
from .welcome import WelcomeModel # NOQA
|
||||
from .identity import IdentityModel # NOQA
|
||||
from .installprogress import InstallProgressModel # NOQA
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
# Copyright 2015 Canonical, Ltd.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# 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 logging
|
||||
from subiquity.model import ModelPolicy
|
||||
|
||||
|
||||
log = logging.getLogger('subiquity.models.installprogress')
|
||||
|
||||
|
||||
class InstallProgressModel(ModelPolicy):
|
||||
""" Model representing install progress
|
||||
"""
|
||||
# FIXME: Decide what to do here if ESC is pressed, it's probably in
|
||||
# a state of no return so may be better to just exit with error.
|
||||
prev_signal = None
|
||||
|
||||
signals = [
|
||||
("Installprogress view",
|
||||
'installprogress:show',
|
||||
'install_progress')
|
||||
]
|
||||
|
||||
installprogress_menu = []
|
||||
|
||||
def get_signals(self):
|
||||
return self.signals
|
||||
|
||||
def get_menu(self):
|
||||
return self.installprogress_menu
|
||||
|
||||
def get_signal_by_name(self, selection):
|
||||
for x, y, z in self.get_menu():
|
||||
if x == selection:
|
||||
return y
|
|
@ -73,7 +73,7 @@ class IdentityView(ViewPolicy):
|
|||
"confirm_password": self.confirm_password.value
|
||||
}
|
||||
log.debug("User input: {}".format(result))
|
||||
# emit_signal(self.signal, 'installpath:show')
|
||||
emit_signal(self.signal, 'installprogress:show')
|
||||
|
||||
def cancel(self, button):
|
||||
self.signal.emit_signal("quit")
|
||||
|
|
|
@ -13,27 +13,25 @@
|
|||
# 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/>.
|
||||
|
||||
from urwid import (Text, Filler, WidgetWrap,
|
||||
import logging
|
||||
from urwid import (Text, Filler,
|
||||
ListBox, BoxAdapter)
|
||||
from subiquity.view import ViewPolicy
|
||||
from subiquity.ui.utils import Color, Padding
|
||||
|
||||
log = logging.getLogger("subiquity.ui.views.installprogress")
|
||||
|
||||
class ProgressOutput(WidgetWrap):
|
||||
def __init__(self, txt):
|
||||
|
||||
class ProgressOutput(ViewPolicy):
|
||||
def __init__(self, signal, txt):
|
||||
self.signal = signal
|
||||
self.txt = Text(txt)
|
||||
flr = Filler(Color.info_minor(self.txt),
|
||||
valign="bottom")
|
||||
valign="top")
|
||||
super().__init__(BoxAdapter(flr, height=20))
|
||||
|
||||
def split_text(self):
|
||||
return self.txt.text.splitlines()
|
||||
|
||||
def set_text(self, data):
|
||||
data = data.decode("utf8")
|
||||
lines = self.split_text() + data.splitlines()
|
||||
out = "\n".join(lines[-20:])
|
||||
self.txt.set_text(out)
|
||||
self.txt.set_text(data)
|
||||
|
||||
|
||||
class ProgressView(ViewPolicy):
|
||||
|
@ -41,6 +39,7 @@ class ProgressView(ViewPolicy):
|
|||
"""
|
||||
:param output_w: Filler widget to display updated status text
|
||||
"""
|
||||
self.signal = signal
|
||||
self.body = [
|
||||
Padding.center_79(output_w)
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue