diff options
Diffstat (limited to 'app/backends/setup.py')
| -rw-r--r-- | app/backends/setup.py | 73 |
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) |
