aboutsummaryrefslogtreecommitdiff
path: root/app/backends/setup.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/backends/setup.py')
-rw-r--r--app/backends/setup.py73
1 files changed, 73 insertions, 0 deletions
diff --git a/app/backends/setup.py b/app/backends/setup.py
new file mode 100644
index 0000000..bd43b92
--- /dev/null
+++ b/app/backends/setup.py
@@ -0,0 +1,73 @@
+"""Shared entry-point plumbing for the backend setup wizards.
+
+Every backend module exposes the same surface — ``_wizard`` (TUI screens),
+``_execute_steps``/``_execute`` (the work, as task-view steps),
+``setup_screen`` (hub-embedded flow), ``run_tui`` (standalone curses
+flow), ``main`` (CLI) — and this module holds the parts of that surface
+that are identical everywhere. The backend keeps the thin named wrappers
+so its public names (and test seams) stay on the backend module.
+"""
+
+import sys
+
+from ui import taskview, tui
+
+
+def interactive() -> bool:
+ """True when the TUI wizard can run (curses importable + tty)."""
+ try:
+ import curses # noqa: F401
+ except ImportError:
+ return False
+ try:
+ return sys.stdin.isatty() and sys.stdout.isatty()
+ except (AttributeError, ValueError):
+ return False
+
+
+def screen_flow(stdscr, *, wizard, steps_of, title,
+ parser_factory) -> int:
+ """Run the setup wizard on an existing curses screen (the hub's).
+
+ The hub drives this as one screen of its own ``tui.Wizard`` stack, so
+ Esc on the wizard's first screen simply returns here and the hub pops
+ back to the menu that launched it. The setup tail runs inside the TUI
+ task view on this same screen, so the hub's curses session stays intact
+ and the user sees per-step status instead of being dropped to the
+ console. Returns 0 on completion, 1 when the user aborted.
+
+ WIZARD is ``(stdscr, args) -> settings | None``; STEPS_OF turns the
+ settings into task-view steps; PARSER_FACTORY builds the argparse
+ parser whose empty namespace seeds the wizard.
+ """
+ args = parser_factory().parse_args([])
+ settings = wizard(stdscr, args)
+ if settings is None:
+ return 1
+ return taskview.run_steps(stdscr, title, steps_of(settings))
+
+
+def tui_flow(wizard, execute, *, args, execute_takes_args=False,
+ aborted_message="[INFO] Aborted") -> int:
+ """Run the setup wizard end-to-end in its own curses session.
+
+ WIZARD is ``(args) -> settings | None`` via ``curses.wrapper``;
+ EXECUTE performs the settings (called with ARGS too when
+ EXECUTE_TAKES_ARGS). Restores the text cursor afterwards and reports
+ cancellation/abort consistently. Returns the process exit code.
+ """
+ import curses
+ try:
+ settings = curses.wrapper(wizard, args)
+ except tui.WizardCancelled:
+ print("\n[INFO] Cancelled; nothing was written")
+ return 1
+ try:
+ curses.curs_set(1)
+ except curses.error:
+ pass
+ if settings is None:
+ print(aborted_message)
+ return 1
+ return execute(settings) if not execute_takes_args \
+ else execute(settings, args)