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:
Adam Stokes 2015-08-23 23:55:45 -04:00
parent 57347582db
commit 709ae2a51a
6 changed files with 108 additions and 27 deletions

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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)
]