clan-vm-manager: Fix ui state desync on build error. Add build progress bar
This commit is contained in:
parent
183c1f4235
commit
0a8b8713d9
@ -99,7 +99,7 @@ def _init_proc(
|
|||||||
gpid = os.getpgid(pid=pid)
|
gpid = os.getpgid(pid=pid)
|
||||||
print(f"Killing process group pid={pid} gpid={gpid}", file=sys.stderr)
|
print(f"Killing process group pid={pid} gpid={gpid}", file=sys.stderr)
|
||||||
os.killpg(gpid, signal.SIGTERM)
|
os.killpg(gpid, signal.SIGTERM)
|
||||||
|
sys.exit(1)
|
||||||
# Don't use a finally block here, because we want the exitcode to be set to
|
# Don't use a finally block here, because we want the exitcode to be set to
|
||||||
# 0 if the function returns normally
|
# 0 if the function returns normally
|
||||||
|
|
||||||
|
@ -136,6 +136,11 @@ class VM(GObject.Object):
|
|||||||
self._logs_id: int = 0
|
self._logs_id: int = 0
|
||||||
self._log_file: IO[str] | None = None
|
self._log_file: IO[str] | None = None
|
||||||
|
|
||||||
|
# To be able to set the switch state programmatically
|
||||||
|
# we need to store the handler id returned by the connect method
|
||||||
|
# and block the signal while we change the state. This is cursed.
|
||||||
|
self.switch_handler_id: int = 0
|
||||||
|
|
||||||
# Make sure the VM is killed when the reference to this object is dropped
|
# Make sure the VM is killed when the reference to this object is dropped
|
||||||
self._finalizer = weakref.finalize(self, self.kill_ref_drop)
|
self._finalizer = weakref.finalize(self, self.kill_ref_drop)
|
||||||
|
|
||||||
@ -171,15 +176,25 @@ class VM(GObject.Object):
|
|||||||
with self.create_machine() as machine:
|
with self.create_machine() as machine:
|
||||||
# Start building VM
|
# Start building VM
|
||||||
log.info(f"Building VM {self.get_id()}")
|
log.info(f"Building VM {self.get_id()}")
|
||||||
|
log_dir = Path(str(self.log_dir.name))
|
||||||
self.build_process = spawn(
|
self.build_process = spawn(
|
||||||
on_except=None,
|
on_except=None,
|
||||||
out_file=Path(str(self.log_dir.name)) / "build.log",
|
out_file=log_dir / "build.log",
|
||||||
func=vms.run.build_vm,
|
func=vms.run.build_vm,
|
||||||
machine=machine,
|
machine=machine,
|
||||||
|
tmpdir=log_dir,
|
||||||
vm=self.data.flake.vm,
|
vm=self.data.flake.vm,
|
||||||
)
|
)
|
||||||
GLib.idle_add(self.emit, "vm_status_changed", self)
|
GLib.idle_add(self.emit, "vm_status_changed", self)
|
||||||
|
|
||||||
|
# Start the logs watcher
|
||||||
|
self._logs_id = GLib.timeout_add(
|
||||||
|
50, self._get_logs_task, self.build_process
|
||||||
|
)
|
||||||
|
if self._logs_id == 0:
|
||||||
|
log.error("Failed to start VM log watcher")
|
||||||
|
log.debug(f"Starting logs watcher on file: {self.build_process.out_file}")
|
||||||
|
|
||||||
# Start the progress bar and show it
|
# Start the progress bar and show it
|
||||||
self.progress_bar.show()
|
self.progress_bar.show()
|
||||||
self.prog_bar_id = GLib.timeout_add(100, self._pulse_progress_bar)
|
self.prog_bar_id = GLib.timeout_add(100, self._pulse_progress_bar)
|
||||||
@ -208,7 +223,7 @@ class VM(GObject.Object):
|
|||||||
GLib.idle_add(self.emit, "vm_status_changed", self)
|
GLib.idle_add(self.emit, "vm_status_changed", self)
|
||||||
|
|
||||||
# Start the logs watcher
|
# Start the logs watcher
|
||||||
self._logs_id = GLib.timeout_add(50, self._get_logs_task)
|
self._logs_id = GLib.timeout_add(50, self._get_logs_task, self.vm_process)
|
||||||
if self._logs_id == 0:
|
if self._logs_id == 0:
|
||||||
log.error("Failed to start VM log watcher")
|
log.error("Failed to start VM log watcher")
|
||||||
log.debug(f"Starting logs watcher on file: {self.vm_process.out_file}")
|
log.debug(f"Starting logs watcher on file: {self.vm_process.out_file}")
|
||||||
@ -223,16 +238,17 @@ class VM(GObject.Object):
|
|||||||
log.warn("VM is already running. Ignoring start request")
|
log.warn("VM is already running. Ignoring start request")
|
||||||
self.emit("vm_status_changed", self)
|
self.emit("vm_status_changed", self)
|
||||||
return
|
return
|
||||||
|
log.debug(f"VM state dir {self.log_dir.name}")
|
||||||
self._start_thread = threading.Thread(target=self.__start)
|
self._start_thread = threading.Thread(target=self.__start)
|
||||||
self._start_thread.start()
|
self._start_thread.start()
|
||||||
|
|
||||||
def _get_logs_task(self) -> bool:
|
def _get_logs_task(self, proc: MPProcess) -> bool:
|
||||||
if not self.vm_process.out_file.exists():
|
if not proc.out_file.exists():
|
||||||
return GLib.SOURCE_CONTINUE
|
return GLib.SOURCE_CONTINUE
|
||||||
|
|
||||||
if not self._log_file:
|
if not self._log_file:
|
||||||
try:
|
try:
|
||||||
self._log_file = open(self.vm_process.out_file)
|
self._log_file = open(proc.out_file)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.exception(ex)
|
log.exception(ex)
|
||||||
self._log_file = None
|
self._log_file = None
|
||||||
@ -242,7 +258,7 @@ class VM(GObject.Object):
|
|||||||
if len(line) != 0:
|
if len(line) != 0:
|
||||||
print(line.decode("utf-8"), end="", flush=True)
|
print(line.decode("utf-8"), end="", flush=True)
|
||||||
|
|
||||||
if not self.is_running():
|
if not proc.proc.is_alive():
|
||||||
log.debug("Removing logs watcher")
|
log.debug("Removing logs watcher")
|
||||||
self._log_file = None
|
self._log_file = None
|
||||||
return GLib.SOURCE_REMOVE
|
return GLib.SOURCE_REMOVE
|
||||||
|
@ -193,11 +193,9 @@ class ClanList(Gtk.Box):
|
|||||||
box.append(switch_box)
|
box.append(switch_box)
|
||||||
box.append(pref_button)
|
box.append(pref_button)
|
||||||
|
|
||||||
switch.connect("notify::active", partial(self.on_row_toggle, vm))
|
vm.switch_handler_id = switch.connect(
|
||||||
# def on_switch_state_set(switch: Any, state: bool) -> bool:
|
"notify::active", partial(self.on_row_toggle, vm)
|
||||||
# return True
|
)
|
||||||
# switch.connect("state-set", on_switch_state_set)
|
|
||||||
|
|
||||||
vm.connect("vm_status_changed", partial(self.vm_status_changed, switch))
|
vm.connect("vm_status_changed", partial(self.vm_status_changed, switch))
|
||||||
|
|
||||||
# suffix.append(box)
|
# suffix.append(box)
|
||||||
@ -304,6 +302,11 @@ class ClanList(Gtk.Box):
|
|||||||
if switch.get_sensitive() is False and not vm.is_building():
|
if switch.get_sensitive() is False and not vm.is_building():
|
||||||
switch.set_sensitive(True)
|
switch.set_sensitive(True)
|
||||||
|
|
||||||
exitc = vm.vm_process.proc.exitcode
|
exit_vm = vm.vm_process.proc.exitcode
|
||||||
|
exit_build = vm.build_process.proc.exitcode
|
||||||
|
exitc = exit_vm or exit_build
|
||||||
if not vm.is_running() and exitc != 0:
|
if not vm.is_running() and exitc != 0:
|
||||||
|
switch.handler_block(vm.switch_handler_id)
|
||||||
|
switch.set_active(False)
|
||||||
|
switch.handler_unblock(vm.switch_handler_id)
|
||||||
log.error(f"VM exited with error. Exitcode: {exitc}")
|
log.error(f"VM exited with error. Exitcode: {exitc}")
|
||||||
|
Loading…
Reference in New Issue
Block a user