tui.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. #!/usr/bin/env python3
  2. # Copyright 2023 The ChromiumOS Authors
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """
  6. Implements styles for `Command.fg(style=)` that use `rich` terminal UI features.
  7. """
  8. import subprocess
  9. from typing import List
  10. from .util import ensure_packages_exist
  11. ensure_packages_exist("rich")
  12. import rich
  13. import rich.console
  14. import rich.live
  15. import rich.spinner
  16. import rich.text
  17. class Styles(object):
  18. "A collection of methods that can be passed to `Command.fg(style=)`"
  19. @staticmethod
  20. def live_truncated(num_lines: int = 8):
  21. "Prints only the last `num_lines` of output while the program is running and successful."
  22. def output(process: "subprocess.Popen[str]"):
  23. assert process.stdout
  24. spinner = rich.spinner.Spinner("dots")
  25. lines: List[rich.text.Text] = []
  26. stdout: List[str] = []
  27. with rich.live.Live(refresh_per_second=30, transient=True) as live:
  28. for line in iter(process.stdout.readline, ""):
  29. stdout.append(line.strip())
  30. lines.append(rich.text.Text.from_ansi(line.strip(), no_wrap=True))
  31. while len(lines) > num_lines:
  32. lines.pop(0)
  33. live.update(rich.console.Group(rich.text.Text("…"), *lines, spinner))
  34. if process.wait() == 0:
  35. console.print(rich.console.Group(rich.text.Text("…"), *lines))
  36. else:
  37. for line in stdout:
  38. print(line)
  39. return output
  40. @staticmethod
  41. def quiet_with_progress(title: str):
  42. "Prints only the last `num_lines` of output while the program is running and successful."
  43. def output(process: "subprocess.Popen[str]"):
  44. assert process.stdout
  45. with rich.live.Live(
  46. rich.spinner.Spinner("dots", title), refresh_per_second=30, transient=True
  47. ):
  48. stdout = process.stdout.read()
  49. if process.wait() == 0:
  50. console.print(f"[green]OK[/green] {title}")
  51. else:
  52. print(stdout)
  53. console.print(f"[red]ERR[/red] {title}")
  54. return output
  55. console = rich.console.Console()