From 15a000daf0be5d4b0ec5af5f23db62ee5d304a64 Mon Sep 17 00:00:00 2001 From: Joongi Kim Date: Wed, 25 Sep 2024 11:46:32 -0700 Subject: [PATCH] fix: Installer regression after upgrading Textual (#2867) Backported-from: main (24.09) Backported-to: 24.03 Backport-of: 2867 --- changes/2867.fix.md | 1 + src/ai/backend/install/context.py | 20 ++++++++------------ src/ai/backend/install/widgets.py | 20 +++++++++++++++++++- 3 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 changes/2867.fix.md diff --git a/changes/2867.fix.md b/changes/2867.fix.md new file mode 100644 index 0000000000..045d126c6e --- /dev/null +++ b/changes/2867.fix.md @@ -0,0 +1 @@ +Fix a regression in progress bar rendering of the TUI installer after upgrading the Textual library diff --git a/src/ai/backend/install/context.py b/src/ai/backend/install/context.py index cd309b2c0e..43124142f0 100644 --- a/src/ai/backend/install/context.py +++ b/src/ai/backend/install/context.py @@ -27,7 +27,7 @@ from rich.text import Text from textual.app import App from textual.containers import Vertical -from textual.widgets import Label, ProgressBar, Static +from textual.widgets import ProgressBar from ai.backend.common.etcd import AsyncEtcd, ConfigScopes @@ -61,7 +61,7 @@ ServerAddr, ServiceConfig, ) -from .widgets import SetupLog +from .widgets import ProgressItem, SetupLog current_log: ContextVar[SetupLog] = ContextVar("current_log") PASSPHRASE_CHARACTER_POOL: Final[list[str]] = ( @@ -1002,11 +1002,9 @@ async def _fetch_package(self, name: str, vpane: Vertical) -> None: pkg_url = f"https://github.com/lablup/backend.ai/releases/download/{self.dist_info.version}/{pkg_name}" csum_url = pkg_url + ".sha256" self.log.write(f"Downloading {pkg_url}...") - item = Static(classes="progress-item") - label = Label(Text.from_markup(f"[blue](download)[/] {pkg_name}"), classes="progress-name") - progress = ProgressBar(classes="progress-download") - item.mount_all([label, progress]) - vpane.mount(item) + item = ProgressItem(f"[blue](download)[/] {pkg_name}") + await vpane.mount(item) + progress = item.get_child_by_type(ProgressBar) async with self.wget_sema: await wget(pkg_url, dst_path, progress) await wget(csum_url, csum_path) @@ -1026,11 +1024,9 @@ async def _install_package(self, name: str, vpane: Vertical, *, fat: bool) -> No pkg_name = self.mangle_pkgname(name, fat=fat) src_path = self.dist_info.package_dir / pkg_name dst_path = self.dist_info.target_path / pkg_name - item = Static(classes="progress-item") - label = Label(Text.from_markup(f"[blue](install)[/] {pkg_name}"), classes="progress-name") - progress = ProgressBar(classes="progress-install") - item.mount_all([label, progress]) - vpane.mount(item) + item = ProgressItem(f"[blue](install)[/] {pkg_name}") + await vpane.mount(item) + progress = item.get_child_by_type(ProgressBar) progress.update(total=src_path.stat().st_size) async with ( aiofiles.open(src_path, "rb") as src, diff --git a/src/ai/backend/install/widgets.py b/src/ai/backend/install/widgets.py index 3416605bba..bfcab8efb8 100644 --- a/src/ai/backend/install/widgets.py +++ b/src/ai/backend/install/widgets.py @@ -11,7 +11,14 @@ from textual.containers import Horizontal from textual.validation import ValidationResult, Validator from textual.widget import Widget -from textual.widgets import Button, Input, Label, RichLog, Static +from textual.widgets import ( + Button, + Input, + Label, + ProgressBar, + RichLog, + Static, +) class DirectoryPathValidator(Validator): @@ -22,6 +29,17 @@ def validate(self, value: str) -> ValidationResult: return self.failure("The path is not a directory") +class ProgressItem(Static): + def __init__(self, label: str, *args, **kwargs) -> None: + kwargs["classes"] = " ".join((kwargs.get("classes", ""), "progress-item")) + super().__init__(*args, **kwargs) + self._label = label + + def compose(self) -> ComposeResult: + yield Label(Text.from_markup(self._label), classes="progress-name") + yield ProgressBar(classes="progress-download") + + class SetupLog(RichLog): BINDINGS = [ Binding("enter", "continue", show=False),