From 51b087f7aecf58077357c827d5e9192fd6540bb4 Mon Sep 17 00:00:00 2001 From: Qubasa Date: Wed, 21 Feb 2024 16:16:58 +0700 Subject: [PATCH] clan-vm-manager: Fix double instantiation of Singleton. clan_cli: Shorten filepath of logging messages --- pkgs/clan-cli/clan_cli/custom_logger.py | 12 +++++-- pkgs/clan-vm-manager/clan_vm_manager/app.py | 34 +++++++------------ .../clan_vm_manager/models/use_vms.py | 9 +++-- .../clan_vm_manager/views/list.py | 7 ++-- .../clan_vm_manager/windows/main_window.py | 17 +++++++++- 5 files changed, 47 insertions(+), 32 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/custom_logger.py b/pkgs/clan-cli/clan_cli/custom_logger.py index 9560f2f5..e3547259 100644 --- a/pkgs/clan-cli/clan_cli/custom_logger.py +++ b/pkgs/clan-cli/clan_cli/custom_logger.py @@ -18,11 +18,14 @@ def get_formatter(color: str) -> Callable[[logging.LogRecord, bool], logging.For ) -> logging.Formatter: reset = "\x1b[0m" filepath = Path(record.pathname).resolve() + home = Path.home() + filepath = Path("~", filepath.relative_to(home)) + if not with_location: return logging.Formatter(f"{color}%(levelname)s{reset}: %(message)s") return logging.Formatter( - f"{color}%(levelname)s{reset}: %(message)s\n {filepath}:%(lineno)d::%(funcName)s\n" + f"{color}%(levelname)s{reset}: %(message)s\nLocation: {filepath}:%(lineno)d::%(funcName)s\n" ) return myformatter @@ -62,7 +65,10 @@ def get_caller() -> str: if caller_frame is None: return "unknown" frame_info = inspect.getframeinfo(caller_frame) - ret = f"{frame_info.filename}:{frame_info.lineno}::{frame_info.function}" + filepath = Path(frame_info.filename).resolve() + filepath = Path("~", filepath.relative_to(Path.home())) + + ret = f"{filepath}:{frame_info.lineno}::{frame_info.function}" return ret @@ -76,7 +82,7 @@ def setup_logging(level: Any, root_log_name: str = __name__.split(".")[0]) -> No # Create and add your custom handler default_handler.setLevel(level) - default_handler.setFormatter(CustomFormatter(level == logging.DEBUG)) + default_handler.setFormatter(CustomFormatter(str(level) == str(logging.DEBUG))) main_logger.addHandler(default_handler) # Set logging level for other modules used by this module diff --git a/pkgs/clan-vm-manager/clan_vm_manager/app.py b/pkgs/clan-vm-manager/clan_vm_manager/app.py index 48c0fb14..1244aa7b 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/app.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/app.py @@ -14,15 +14,19 @@ from gi.repository import Adw, Gdk, Gio, Gtk from clan_vm_manager.models.interfaces import ClanConfig from clan_vm_manager.models.use_join import GLib, GObject -from clan_vm_manager.models.use_vms import VMs -from .trayicon import TrayIcon from .windows.main_window import MainWindow log = logging.getLogger(__name__) class MainApplication(Adw.Application): + """ + This class is initialized every time the app is started + Only the Adw.ApplicationWindow is a singleton. + So don't use any singletons in the Adw.Application class. + """ + __gsignals__: ClassVar = { "join_request": (GObject.SignalFlags.RUN_FIRST, None, [str]), } @@ -34,7 +38,6 @@ class MainApplication(Adw.Application): flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE, **kwargs, ) - self.tray_icon: TrayIcon | None = None self.add_main_option( "debug", @@ -44,10 +47,8 @@ class MainApplication(Adw.Application): "enable debug mode", None, ) - self.vms = VMs.use() - log.debug(f"VMS object: {self.vms}") + self.window: Adw.ApplicationWindow | None = None - self.connect("shutdown", self.on_shutdown) self.connect("activate", self.show_window) def do_command_line(self, command_line: Any) -> int: @@ -56,10 +57,10 @@ class MainApplication(Adw.Application): options = options.end().unpack() if "debug" in options: - setup_logging("DEBUG", root_log_name=__name__.split(".")[0]) - setup_logging("DEBUG", root_log_name="clan_cli") + setup_logging(logging.DEBUG, root_log_name=__name__.split(".")[0]) + setup_logging(logging.DEBUG, root_log_name="clan_cli") else: - setup_logging("INFO", root_log_name=__name__.split(".")[0]) + setup_logging(logging.INFO, root_log_name=__name__.split(".")[0]) log.debug("Debug logging enabled") args = command_line.get_arguments() @@ -72,14 +73,6 @@ class MainApplication(Adw.Application): self.emit("join_request", uri) return 0 - def on_shutdown(self, app: Gtk.Application) -> None: - log.debug("Shutting down") - - self.vms.kill_all() - - if self.tray_icon is not None: - self.tray_icon.destroy() - def on_window_hide_unhide(self, *_args: Any) -> None: assert self.window is not None if self.window.is_visible(): @@ -90,15 +83,12 @@ class MainApplication(Adw.Application): def dummy_menu_entry(self) -> None: log.info("Dummy menu entry called") - def do_activate(self) -> None: - self.show_window() - - def show_window(self, app: Any = None) -> None: + def show_window(self, *_args: Any) -> None: if not self.window: self.init_style() self.window = MainWindow(config=ClanConfig(initial_view="list")) self.window.set_application(self) - self.tray_icon = TrayIcon(self) + self.window.present() # TODO: For css styling diff --git a/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py b/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py index fbefec06..7ba8b7b8 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/models/use_vms.py @@ -122,7 +122,7 @@ class VM(GObject.Object): self.log_dir = tempfile.TemporaryDirectory( prefix="clan_vm-", suffix=f"-{self.data.flake.flake_attr}" ) - self._finalizer = weakref.finalize(self, self.kill) + self._finalizer = weakref.finalize(self, self.kill_ref_drop) self.connect("build_vm", self.build_vm) uri = ClanURI.from_str( url=self.data.flake.flake_url, flake_attr=self.data.flake.flake_attr @@ -269,6 +269,11 @@ class VM(GObject.Object): log.info(f"Stopping VM {self.get_id()}") threading.Thread(target=self.__stop).start() + def kill_ref_drop(self) -> None: + if self.is_running(): + log.warning("Killing VM due to reference drop") + self.kill() + def kill(self) -> None: if not self.is_running(): log.warning(f"Tried to kill VM {self.get_id()} is not running") @@ -315,14 +320,12 @@ class VMs: for vm in self.list_store: if ident == vm.get_id(): return vm - return None def get_running_vms(self) -> list[VM]: return list(filter(lambda vm: vm.is_running(), self.list_store)) def kill_all(self) -> None: - log.debug(f"Running vms: {self.get_running_vms()}") for vm in self.get_running_vms(): vm.kill() diff --git a/pkgs/clan-vm-manager/clan_vm_manager/views/list.py b/pkgs/clan-vm-manager/clan_vm_manager/views/list.py index ed529675..2ab4395d 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/views/list.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/views/list.py @@ -10,6 +10,7 @@ from clan_cli.clan_uri import ClanURI from clan_vm_manager.models.interfaces import ClanConfig from clan_vm_manager.models.use_join import Join, JoinValue from clan_vm_manager.models.use_views import Views +from clan_vm_manager.models.use_vms import VMs gi.require_version("Adw", "1") from gi.repository import Adw, Gdk, Gio, GLib, GObject, Gtk @@ -123,7 +124,7 @@ class ClanList(Gtk.Box): def on_search_changed(self, entry: Gtk.SearchEntry) -> None: Clans.use().filter_by_name(entry.get_text()) # Disable the shadow if the list is empty - if not self.app.vms.list_store.get_n_items(): + if not VMs.use().list_store.get_n_items(): self.group_list.add_css_class("no-shadow") def render_vm_row(self, boxed_list: Gtk.ListBox, vm: VM) -> Gtk.Widget: @@ -202,7 +203,7 @@ class ClanList(Gtk.Box): def on_edit(self, action: Any, parameter: Any) -> None: target = parameter.get_string() - vm = self.app.vms.get_by_id(target) + vm = VMs.use().get_by_id(target) if not vm: raise ClanError("Something went wrong. Please restart the app.") @@ -220,7 +221,7 @@ class ClanList(Gtk.Box): row.add_css_class("trust") # TODO: figure out how to detect that - exist = self.app.vms.use().get_by_id(item.url.get_id()) + exist = VMs.use().use().get_by_id(item.url.get_id()) if exist: sub = row.get_subtitle() row.set_subtitle( diff --git a/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py b/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py index 19329ba9..5720e045 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py @@ -1,13 +1,18 @@ +from typing import Any + import gi from clan_vm_manager.models.interfaces import ClanConfig from clan_vm_manager.models.use_views import Views +from clan_vm_manager.models.use_vms import VMs from clan_vm_manager.views.details import Details from clan_vm_manager.views.list import ClanList gi.require_version("Adw", "1") -from gi.repository import Adw, Gtk +from gi.repository import Adw, Gio, Gtk + +from ..trayicon import TrayIcon class MainWindow(Adw.ApplicationWindow): @@ -22,6 +27,10 @@ class MainWindow(Adw.ApplicationWindow): header = Adw.HeaderBar() view.add_top_bar(header) + self.vms = VMs.use() + app = Gio.Application.get_default() + self.tray_icon: TrayIcon = TrayIcon(app) + # Initialize all views stack_view = Views.use().view Views.use().set_main_window(self) @@ -41,3 +50,9 @@ class MainWindow(Adw.ApplicationWindow): clamp.set_maximum_size(1000) view.set_content(clamp) + + self.connect("destroy", self.on_destroy) + + def on_destroy(self, *_args: Any) -> None: + self.tray_icon.destroy() + self.vms.kill_all()