| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- # -*- coding: utf-8 -*-
- """
- InstallerApp — Haupteinstieg der Trixy Installer TUI.
- Gestartet via: python app.py --mode server --version 1.0.0 --source-archive pfad.tar.gz
- """
- from __future__ import annotations
- import argparse
- import sys
- from pathlib import Path
- from textual.app import App, ComposeResult
- from textual.binding import Binding
- from .config import InstallerConfig
- from .menu_context import MenuBinding, MenuContext
- from .widgets.header import InstallerHeader
- from .widgets.footer import InstallerFooter
- from .views.base import InstallerView
- from .views.system_view import SystemView
- from .views.network_view import NetworkView
- from .views.plugins_view import PluginsView
- from .views.requirements_view import RequirementsView
- from .views.agreement_view import AgreementView
- from .views.install_view import InstallView
- class InstallerApp(App):
- """Trixy Installer TUI-Anwendung."""
- CSS_PATH = "css/installer.tcss"
- TITLE = "Trixy Installer"
- BINDINGS = [
- Binding("f1", "fkey('f1')", "F1", show=False),
- Binding("f2", "fkey('f2')", "F2", show=False),
- Binding("f3", "fkey('f3')", "F3", show=False),
- Binding("f4", "fkey('f4')", "F4", show=False),
- Binding("f5", "fkey('f5')", "F5", show=False),
- Binding("f6", "fkey('f6')", "F6", show=False),
- Binding("q", "quit", "Beenden", show=False),
- ]
- def __init__(self, config: InstallerConfig, existing: "ExistingInstallation | None" = None) -> None:
- super().__init__()
- self._config = config
- self._existing = existing
- self._views: list[InstallerView] = []
- self._view_map: dict[str, InstallerView] = {}
- self._active_view: InstallerView | None = None
- self._menu = MenuContext()
- self._fkey_map: dict[str, str] = {}
- def compose(self) -> ComposeResult:
- yield InstallerHeader(
- version=self._config.version,
- mode=self._config.mode,
- id="header",
- )
- # Views erstellen — nur fuer den aktuellen Modus
- mode = self._config.mode
- all_views: list[InstallerView] = [
- SystemView(self._config, id="view-system"),
- NetworkView(self._config, id="view-network"),
- PluginsView(self._config, id="view-plugins"),
- RequirementsView(self._config, id="view-requirements"),
- AgreementView(self._config, id="view-agreement"),
- InstallView(self._config, existing=self._existing, id="view-install"),
- ]
- # Tab-Definitionen: (f-key, view)
- tab_defs = [
- ("f1", all_views[0]), # System
- ("f2", all_views[1]), # Netzwerk
- ("f3", all_views[2]), # Plugins
- ("f4", all_views[3]), # Pakete
- ("f5", all_views[4]), # Vereinbarung
- ("f6", all_views[5]), # Installation
- ]
- for fkey, view in tab_defs:
- if mode in view.MODES:
- self._views.append(view)
- self._view_map[view.VIEW_ID] = view
- self._fkey_map[fkey] = view.VIEW_ID
- self._menu.add(MenuBinding(
- key=fkey,
- label=view.TITLE,
- view_id=view.VIEW_ID,
- ))
- view.display = False
- yield view
- yield InstallerFooter(self._menu, id="footer")
- async def on_mount(self) -> None:
- """Aktiviert den ersten View nach dem Mount."""
- if self._views:
- await self._activate_view(self._views[0].VIEW_ID)
- async def action_fkey(self, key: str) -> None:
- """Verarbeitet F-Tasten-Druecke."""
- view_id = self._fkey_map.get(key)
- if view_id and view_id in self._view_map:
- await self._activate_view(view_id)
- async def _activate_view(self, view_id: str) -> None:
- """Aktiviert einen View und deaktiviert den aktuellen."""
- new_view = self._view_map.get(view_id)
- if not new_view or new_view is self._active_view:
- return
- # Alten View deaktivieren
- if self._active_view:
- await self._active_view.on_deactivate()
- self._active_view.display = False
- # Neuen View aktivieren
- new_view.display = True
- self._active_view = new_view
- await new_view.on_activate()
- # Header aktualisieren
- header = self.query_one("#header", InstallerHeader)
- header.subtitle = new_view.TITLE
- def main() -> None:
- """CLI-Einstiegspunkt."""
- parser = argparse.ArgumentParser(description="Trixy Installer")
- parser.add_argument(
- "--mode",
- choices=["server", "client", "standalone", "config"],
- required=True,
- help="Installationsmodus",
- )
- parser.add_argument("--version", default="1.0.0", help="Trixy-Version")
- parser.add_argument("--source-archive", default="", help="Pfad zum Quellarchiv (.tar.gz)")
- parser.add_argument("--install-path", default="", help="Installationspfad (ueberschreibt Default)")
- args = parser.parse_args()
- config = InstallerConfig(
- mode=args.mode,
- version=args.version,
- source_archive=args.source_archive,
- )
- if args.install_path:
- config.install_path = args.install_path
- # Bestehende Installation erkennen
- from .detect import detect_installation, apply_existing_to_config
- existing = detect_installation(config.install_path, config.mode, config.version)
- if existing.found:
- apply_existing_to_config(existing, config)
- app = InstallerApp(config, existing=existing)
- app.run()
- if __name__ == "__main__":
- main()
|