clan-core/pkgs/clan-vm-manager/clan_vm_manager/app.py

166 lines
5.0 KiB
Python
Raw Normal View History

2023-11-25 00:55:01 +00:00
#!/usr/bin/env python3
2023-12-16 11:52:10 +00:00
import argparse
from dataclasses import dataclass
from pathlib import Path
2023-12-16 12:03:10 +00:00
2023-11-25 00:55:01 +00:00
import gi
from clan_cli import vms
2023-12-16 12:03:10 +00:00
2023-12-30 10:14:45 +00:00
from clan_vm_manager.windows.flash import FlashUSBWindow
2023-11-25 00:55:01 +00:00
gi.require_version("Gtk", "3.0")
2023-12-16 11:52:10 +00:00
from clan_cli.clan_uri import ClanURI
2023-12-16 12:03:10 +00:00
from gi.repository import Gio, Gtk
2023-11-28 17:19:01 +00:00
from .constants import constants
from .executor import ProcessManager
2023-12-30 10:14:45 +00:00
from .interfaces import Callbacks, InitialFlashValues, InitialJoinValues
2023-12-16 11:52:10 +00:00
from .windows.join import JoinWindow
from .windows.overview import OverviewWindow
2023-12-16 12:03:10 +00:00
2023-12-16 11:52:10 +00:00
@dataclass
2023-12-16 12:03:10 +00:00
class ClanWindows:
2023-12-16 12:05:17 +00:00
join: type[JoinWindow]
overview: type[OverviewWindow]
2023-12-30 10:14:45 +00:00
flash_usb: type[FlashUSBWindow]
2023-12-16 12:05:17 +00:00
2023-11-28 17:19:01 +00:00
2023-12-16 11:52:10 +00:00
@dataclass
2023-12-16 12:03:10 +00:00
class ClanConfig:
2023-12-16 11:52:10 +00:00
initial_window: str
2023-12-16 12:04:50 +00:00
url: ClanURI | None
2023-12-16 12:05:17 +00:00
2023-11-28 18:55:40 +00:00
2023-11-28 17:19:01 +00:00
class Application(Gtk.Application):
2023-12-16 11:52:10 +00:00
def __init__(self, windows: ClanWindows, config: ClanConfig) -> None:
2023-11-28 17:19:01 +00:00
super().__init__(
application_id=constants["APPID"], flags=Gio.ApplicationFlags.FLAGS_NONE
)
self.init_style()
2023-12-16 11:52:10 +00:00
self.windows = windows
self.proc_manager = ProcessManager()
2023-12-16 11:52:10 +00:00
initial = windows.__dict__[config.initial_window]
self.cbs = Callbacks(
show_list=self.show_list,
show_join=self.show_join,
2023-12-30 10:14:45 +00:00
show_flash=self.show_flash,
spawn_vm=self.spawn_vm,
stop_vm=self.stop_vm,
running_vms=self.running_vms,
)
2023-12-16 12:05:17 +00:00
if issubclass(initial, JoinWindow):
2023-12-16 11:52:10 +00:00
# see JoinWindow constructor
2023-12-16 12:05:17 +00:00
self.window = initial(
initial_values=InitialJoinValues(url=config.url or ""),
2023-12-16 13:49:08 +00:00
cbs=self.cbs,
2023-12-16 12:05:17 +00:00
)
2023-12-16 11:52:10 +00:00
2023-12-16 12:05:17 +00:00
if issubclass(initial, OverviewWindow):
2023-12-16 11:52:10 +00:00
# see OverviewWindow constructor
2023-12-16 13:49:08 +00:00
self.window = initial(cbs=self.cbs)
2023-12-16 11:52:10 +00:00
# Connect to the shutdown signal
self.connect("shutdown", self.on_shutdown)
def on_shutdown(self, app: Gtk.Application) -> None:
print("Shutting down")
self.proc_manager.kill_all()
def spawn_vm(self, url: str, attr: str) -> None:
print(f"spawn_vm {url}")
# TODO: We should use VMConfig from the history file
vm = vms.run.inspect_vm(flake_url=url, flake_attr=attr)
log_path = Path(".")
# TODO: We only use the url as the ident. This is not unique as the flake_attr is missing.
# when we migrate everything to use the ClanURI class we can use the full url as the ident
self.proc_manager.spawn(
ident=url,
wait_stdin_con=False,
log_path=log_path,
func=vms.run.run_vm,
vm=vm,
)
def stop_vm(self, url: str, attr: str) -> None:
print(f"stop_vm {url}")
self.proc_manager.kill(url)
def running_vms(self) -> list[str]:
return list(self.proc_manager.procs.keys())
2023-12-16 12:05:17 +00:00
def show_list(self) -> None:
2023-12-16 11:52:10 +00:00
prev = self.window
2023-12-16 13:49:08 +00:00
self.window = self.windows.__dict__["overview"](cbs=self.cbs)
self.window.set_application(self)
2023-12-16 11:52:10 +00:00
prev.hide()
2023-12-16 13:49:08 +00:00
def show_join(self) -> None:
2023-12-16 11:52:10 +00:00
prev = self.window
2023-12-16 13:49:08 +00:00
self.window = self.windows.__dict__["join"](
cbs=self.cbs, initial_values=InitialJoinValues(url=None)
2023-12-16 13:49:08 +00:00
)
self.window.set_application(self)
2023-12-16 11:52:10 +00:00
prev.hide()
2023-11-28 17:19:01 +00:00
2023-12-30 10:14:45 +00:00
def show_flash(self) -> None:
prev = self.window
self.window = self.windows.__dict__["flash_usb"](
cbs=self.cbs, initial_values=FlashUSBWindow(InitialFlashValues(None))
)
self.window.set_application(self)
2023-12-30 10:14:45 +00:00
prev.hide()
2023-11-30 12:42:15 +00:00
def do_startup(self) -> None:
2023-11-28 17:19:01 +00:00
Gtk.Application.do_startup(self)
2023-12-06 17:38:19 +00:00
Gtk.init()
2023-11-28 17:19:01 +00:00
2023-11-30 12:42:15 +00:00
def do_activate(self) -> None:
2023-11-28 17:19:01 +00:00
win = self.props.active_window
if not win:
2023-12-08 10:56:27 +00:00
win = self.window
win.set_application(self)
2023-11-28 17:19:01 +00:00
win.present()
# TODO: For css styling
2023-11-30 12:42:15 +00:00
def init_style(self) -> None:
2023-11-28 17:19:01 +00:00
pass
# css_provider = Gtk.CssProvider()
# css_provider.load_from_resource(constants['RESOURCEID'] + '/style.css')
# screen = Gdk.Screen.get_default()
# style_context = Gtk.StyleContext()
# style_context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
2023-12-16 11:52:10 +00:00
def show_join(args: argparse.Namespace) -> None:
print(f"Joining clan {args.clan_uri}")
2023-12-16 12:05:17 +00:00
app = Application(
2023-12-30 10:14:45 +00:00
windows=ClanWindows(
join=JoinWindow, overview=OverviewWindow, flash_usb=FlashUSBWindow
),
2023-12-16 12:05:17 +00:00
config=ClanConfig(url=args.clan_uri, initial_window="join"),
)
2023-12-16 11:52:10 +00:00
return app.run()
def register_join_parser(parser: argparse.ArgumentParser) -> None:
parser.add_argument("clan_uri", type=ClanURI, help="clan URI to join")
parser.set_defaults(func=show_join)
def show_overview(args: argparse.Namespace) -> None:
2023-12-16 12:05:17 +00:00
app = Application(
2023-12-30 10:14:45 +00:00
windows=ClanWindows(
join=JoinWindow, overview=OverviewWindow, flash_usb=FlashUSBWindow
),
2023-12-16 12:05:17 +00:00
config=ClanConfig(url=None, initial_window="overview"),
)
2023-12-16 11:52:10 +00:00
return app.run()
def register_overview_parser(parser: argparse.ArgumentParser) -> None:
parser.set_defaults(func=show_overview)