Merge pull request 'Added show_error_dialogue on exception' (#674) from Qubasa-main into main
This commit is contained in:
commit
1fc524e53e
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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:
|
||||
|
@ -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}")
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user