1
0
forked from clan/clan-core

Added show_error_dialogue on exception

This commit is contained in:
Luis Hebendanz 2024-01-02 05:54:19 +01:00
parent 9ec1d594e7
commit c157ecb161
5 changed files with 46 additions and 22 deletions

View File

@ -10,10 +10,13 @@ from clan_vm_manager.windows.flash import FlashUSBWindow
gi.require_version("Gtk", "3.0")
import multiprocessing as mp
from clan_cli.clan_uri import ClanURI
from gi.repository import Gio, Gtk
from .constants import constants
from .errors.show_error import show_error_dialog
from .executor import ProcessManager
from .interfaces import Callbacks, InitialFlashValues, InitialJoinValues
from .windows.join import JoinWindow
@ -33,6 +36,11 @@ class ClanConfig:
url: ClanURI | None
# Will be executed in the context of the child process
def on_except(error: Exception, proc: mp.process.BaseProcess) -> None:
show_error_dialog(str(error))
class Application(Gtk.Application):
def __init__(self, windows: ClanWindows, config: ClanConfig) -> None:
super().__init__(
@ -80,17 +88,17 @@ class Application(Gtk.Application):
self.proc_manager.spawn(
ident=url,
wait_stdin_con=False,
on_except=on_except,
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())
return self.proc_manager.running_procs()
def show_list(self) -> None:
prev = self.window

View File

@ -21,10 +21,6 @@ def _kill_group(proc: mp.Process) -> None:
pid = proc.pid
assert pid is not None
if proc.is_alive():
print(
f"Killing process group pid={pid}",
file=sys.stderr,
)
os.killpg(pid, signal.SIGTERM)
else:
print(f"Process {proc.name} with pid {pid} is already dead", file=sys.stderr)
@ -67,6 +63,7 @@ def _init_proc(
in_file: Path,
wait_stdin_connect: bool,
proc_name: str,
on_except: Callable[[Exception, mp.process.BaseProcess], None],
**kwargs: Any,
) -> None:
# Create a new process group
@ -97,8 +94,9 @@ def _init_proc(
print(f"Executing function {func.__name__} now", file=sys.stderr)
try:
func(**kwargs)
except Exception:
except Exception as ex:
traceback.print_exc()
on_except(ex, mp.current_process())
finally:
pid = os.getpid()
gpid = os.getpgid(pid=pid)
@ -107,12 +105,16 @@ def _init_proc(
def spawn(
*, wait_stdin_con: bool, log_path: Path, func: Callable, **kwargs: Any
*,
wait_stdin_con: bool,
log_path: Path,
on_except: Callable[[Exception, mp.process.BaseProcess], None],
func: Callable,
**kwargs: Any,
) -> MPProcess:
# Decouple the process from the parent
if mp.get_start_method(allow_none=True) is None:
mp.set_start_method(method="forkserver")
print("Set mp start method to forkserver", file=sys.stderr)
if not log_path.is_dir():
raise ClanError(f"Log path {log_path} is not a directory")
@ -132,7 +134,7 @@ def spawn(
# Start the process
proc = mp.Process(
target=_init_proc,
args=(func, out_file, in_file, wait_stdin_con, proc_name),
args=(func, out_file, in_file, wait_stdin_con, proc_name, on_except),
name=proc_name,
kwargs=kwargs,
)
@ -140,8 +142,6 @@ def spawn(
# Print some information
assert proc.pid is not None
print(f"Started process '{proc_name}'")
print(f"Arguments: {kwargs}")
if wait_stdin_con:
cmd = f"cat - > {in_file}"
@ -166,17 +166,42 @@ class ProcessManager:
self.procs: dict[str, MPProcess] = dict()
self._finalizer = weakref.finalize(self, self.kill_all)
def by_pid(self, pid: int) -> tuple[str, MPProcess] | None:
for ident, proc in self.procs.items():
if proc.proc.pid == pid:
return (ident, proc)
return None
def by_proc(self, proc: mp.process.BaseProcess) -> tuple[str, MPProcess] | None:
if proc.pid is None:
return None
return self.by_pid(pid=proc.pid)
def running_procs(self) -> list[str]:
res = []
for ident, proc in self.procs.copy().items():
if proc.proc.is_alive():
res.append(ident)
else:
del self.procs[ident]
return res
def spawn(
self,
*,
ident: str,
wait_stdin_con: bool,
log_path: Path,
on_except: Callable[[Exception, mp.process.BaseProcess], None],
func: Callable,
**kwargs: Any,
) -> MPProcess:
proc = spawn(
wait_stdin_con=wait_stdin_con, log_path=log_path, func=func, **kwargs
wait_stdin_con=wait_stdin_con,
log_path=log_path,
on_except=on_except,
func=func,
**kwargs,
)
if ident in self.procs:
raise ClanError(f"Process with id {ident} already exists")

View File

@ -123,32 +123,26 @@ class ClanList(Gtk.Box):
)
def on_flash_clicked(self, widget: Gtk.Widget) -> None:
print("Flash clicked")
self.cbs.show_flash()
def on_double_click(self, vm: VMBase) -> None:
print(f"on_double_click: {vm.name}")
self.on_start_clicked(self)
def on_start_clicked(self, widget: Gtk.Widget) -> None:
print("Start clicked")
if self.selected_vm:
self.cbs.spawn_vm(self.selected_vm.url, self.selected_vm._flake_attr)
# Call this to reload
self.remount_list_view()
def on_stop_clicked(self, widget: Gtk.Widget) -> None:
print("Stop clicked")
if self.selected_vm:
self.cbs.stop_vm(self.selected_vm.url, self.selected_vm._flake_attr)
self.remount_list_view()
def on_new_clicked(self, widget: Gtk.Widget) -> None:
print("New clicked")
self.show_join()
def on_edit_clicked(self, widget: Gtk.Widget) -> None:
print("Edit clicked")
self.remount_edit_view()
def on_select_vm(self, vm: VMBase) -> None:

View File

@ -75,7 +75,6 @@ class Trust(Gtk.Box):
self.set_center_widget(layout)
def on_trust(self, widget: Gtk.Widget) -> None:
# TODO: @Johannes, replace image with real clan logo
try:
uri = self.url or ClanURI(self.entry.get_text())
print(f"trusted: {uri}")

View File

@ -54,7 +54,6 @@ class OverviewWindow(Gtk.ApplicationWindow):
def remount_list_view(self) -> None:
widget = self.stack.get_child_by_name("list")
print("Remounting ClanListView")
if widget:
widget.destroy()
@ -71,7 +70,6 @@ class OverviewWindow(Gtk.ApplicationWindow):
self.stack.set_visible_child_name("list")
def remount_edit_view(self) -> None:
print("Remounting ClanEdit")
widget = self.stack.get_child_by_name("edit")
if widget:
widget.destroy()