From b5eb76b985b506f3586a86fe832f3ff8ec5109d7 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Wed, 18 Jan 2017 15:13:48 +1300 Subject: [PATCH] show entire log, incrementally need to figure out how to scroll to end on each update --- subiquity/controllers/installprogress.py | 38 ++++++++++++++++++++++-- subiquity/ui/views/installprogress.py | 14 ++++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/subiquity/controllers/installprogress.py b/subiquity/controllers/installprogress.py index c66bf4e2..4d5587e4 100644 --- a/subiquity/controllers/installprogress.py +++ b/subiquity/controllers/installprogress.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 fcntl import logging import os import subprocess @@ -54,6 +55,7 @@ class InstallProgressController(BaseController): self.progress_view = None self.install_state = InstallState.NOT_STARTED self.postinstall_written = False + self.tail_proc = None def curtin_wrote_install(self): pass @@ -149,7 +151,12 @@ class InstallProgressController(BaseController): self.install_state = InstallState.RUNNING_POSTINSTALL if self.progress_view is not None: + self.progress_view.clear_log_tail() self.progress_view.set_status("Running postinstall step.") + if self.tail_proc is not None: + self.loop.remove_watch_file(self.tail_watcher_handle) + self.tail_proc.terminate() + self.tail_proc = None if self.opts.dry_run: log.debug("Installprogress: this is a dry-run") curtin_cmd = [ @@ -177,6 +184,31 @@ class InstallProgressController(BaseController): log.debug('After curtin postinstall OK') self.install_state = InstallState.DONE_POSTINSTALL + def update_log_tail(self): + if self.tail_proc is None: + return + tail = self.tail_proc.stdout.read().decode('utf-8', 'replace') + self.progress_view.add_log_tail(tail) + + def maybe_start_tail_proc(self): + if self.install_state < InstallState.RUNNING_POSTINSTALL: + install_log = CURTIN_INSTALL_LOG + else: + install_log = CURTIN_POSTINSTALL_LOG + if os.path.exists(install_log): + self.progress_view.clear_log_tail() + tail_cmd = ['tail', '-n', '1000', '-f', install_log] + log.debug('tail cmd: {}'.format(" ".join(tail_cmd))) + self.tail_proc = utils.run_command_start(tail_cmd) + stdout_fileno = self.tail_proc.stdout.fileno() + fcntl.fcntl( + stdout_fileno, fcntl.F_SETFL, + fcntl.fcntl(stdout_fileno, fcntl.F_GETFL) | os.O_NONBLOCK) + self.tail_watcher_handle = self.loop.watch_file(stdout_fileno, self.update_log_tail) + else: + log.debug(('Install log not yet present:') + + '{}'.format(install_log)) + def progress_indicator(self, *args, **kwargs): if self.install_state == InstallState.ERROR: log.debug('progress_indicator: error detected') @@ -185,10 +217,10 @@ class InstallProgressController(BaseController): log.debug('progress_indicator: complete!') self.ui.set_footer("", 100) self.progress_view.show_complete() + elif self.tail_proc is None: + self.maybe_start_tail_proc() + self.loop.set_alarm_in(0.3, self.progress_indicator) else: - log.debug('progress_indicator: looping') - install_tail = self.curtin_tail_install_log() - self.progress_view.set_log_tail(install_tail) self.loop.set_alarm_in(0.3, self.progress_indicator) def reboot(self): diff --git a/subiquity/ui/views/installprogress.py b/subiquity/ui/views/installprogress.py index 6b311a27..294ea545 100644 --- a/subiquity/ui/views/installprogress.py +++ b/subiquity/ui/views/installprogress.py @@ -34,19 +34,25 @@ class ProgressView(BaseView): self.controller = controller self.error = Text("") self.status = Text("Running install step.") - self.log = Text("") + self.listbox = ListBox([Text("")]) body = [ ('pack', Padding.center_79(self.error)), ('pack', Padding.center_79(self.status)), ('pack', Text("")), - ('weight', 1, Padding.center_79(LineBox(ListBox([self.log]), title="Installation logs"))), + ('weight', 1, Padding.center_79(LineBox(self.listbox, title="Installation logs"))), ('pack', Text("")), ] self.pile = Pile(body) super().__init__(self.pile) - def set_log_tail(self, text): - self.log.set_text(text) + def add_log_tail(self, text): + if text.endswith('\n'): + text = text[:-1] + self.listbox.body.contents.append(Text(text)) + self.listbox.set_focus_valign('bottom') + + def clear_log_tail(self): + self.listbox.body.contents[:] = [] def set_status(self, text): self.status.set_text(text)