Skip to content

Commit d627dba

Browse files
committed
Refactor compilation process to run in a separate thread
1 parent 5aa3eb2 commit d627dba

1 file changed

Lines changed: 117 additions & 77 deletions

File tree

  • Core/engines_loader/engines_only_mod

Core/engines_loader/engines_only_mod/gui.py

Lines changed: 117 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from typing import Optional, Dict, Any, List
3636
from datetime import datetime
3737

38-
from PySide6.QtCore import Qt, QSize, QTimer
38+
from PySide6.QtCore import Qt, QSize, QTimer, QProcess, QThread
3939
from PySide6.QtWidgets import (
4040
QApplication,
4141
QMainWindow,
@@ -71,6 +71,60 @@
7171
import Core.engines_loader as engines_loader
7272

7373

74+
class CompilationThread(QThread):
75+
"""Thread pour exécuter la compilation sans bloquer l'UI."""
76+
77+
output_ready = None # Signal(str)
78+
error_ready = None # Signal(str)
79+
finished = None # Signal(int) - code de retour
80+
81+
def __init__(self, program, args, env, working_dir=None):
82+
super().__init__()
83+
self.program = program
84+
self.args = args
85+
self.env = env
86+
self.working_dir = working_dir
87+
88+
def run(self):
89+
"""Exécute le processus de compilation."""
90+
try:
91+
proc = subprocess.Popen(
92+
[self.program] + self.args,
93+
stdout=subprocess.PIPE,
94+
stderr=subprocess.PIPE,
95+
text=True,
96+
env=self.env,
97+
cwd=self.working_dir,
98+
bufsize=1,
99+
)
100+
101+
# Lire la sortie en temps réel
102+
while True:
103+
line = proc.stdout.readline()
104+
if not line and proc.poll() is not None:
105+
break
106+
if line and self.output_ready:
107+
self.output_ready.emit(line.rstrip())
108+
109+
# Lire stderr à la fin
110+
stderr = proc.stderr.read()
111+
if stderr and self.error_ready:
112+
for line in stderr.strip().split("\n"):
113+
if line:
114+
self.error_ready.emit(line.rstrip())
115+
116+
# Signaler la fin
117+
return_code = proc.wait()
118+
if self.finished:
119+
self.finished.emit(return_code)
120+
121+
except Exception as e:
122+
if self.error_ready:
123+
self.error_ready.emit(f"Error: {str(e)}")
124+
if self.finished:
125+
self.finished.emit(1)
126+
127+
74128
class EnginesStandaloneGui(QMainWindow):
75129
"""
76130
Application autonome GUI pour gérer et exécuter les moteurs de compilation.
@@ -647,21 +701,6 @@ def _refresh_engines(self):
647701
except Exception as e:
648702
self._log(f"Error loading engine {eid}: {e}")
649703

650-
def _on_engine_changed(self, index):
651-
"""Appelé lorsque l'utilisateur sélectionne un moteur via l'onglet."""
652-
if index < 0:
653-
return
654-
655-
# Récupérer l'ID du moteur depuis le registry
656-
try:
657-
engine_id = engines_loader.registry.get_engine_for_tab(index)
658-
self.selected_engine_id = engine_id
659-
if engine_id and engine_id in self.engines_info:
660-
info = self.engines_info[engine_id]
661-
self._log(f"Selected engine: {info['name']} v{info['version']}")
662-
except Exception as e:
663-
self._log(f"Error getting engine for tab {index}: {e}")
664-
665704
def _create_default_engine_widget(
666705
self, engine_id: str, name: str, version: str, required_core: str
667706
) -> QWidget:
@@ -856,8 +895,12 @@ def _run_compilation(self):
856895
self._log("=" * 50)
857896

858897
try:
859-
# Créer le moteur
860-
engine = create_engine(engine_id)
898+
# Get the engine instance from registry (has the tab configuration)
899+
engine = engines_loader.registry.get_instance(engine_id)
900+
901+
# If no stored instance, create one (fallback)
902+
if not engine:
903+
engine = create_engine(engine_id)
861904

862905
# Préparer les arguments avec le GUI pour accéder aux options
863906
result = engine.program_and_args(self, file_path)
@@ -874,65 +917,19 @@ def _run_compilation(self):
874917
if self.workspace_dir:
875918
env["ARK_WORKSPACE"] = self.workspace_dir
876919

877-
# Exécuter la commande
920+
# Exécuter la commande dans un thread séparé
878921
self._log("Executing...")
879922

880-
proc = subprocess.Popen(
881-
cmd,
882-
stdout=subprocess.PIPE,
883-
stderr=subprocess.PIPE,
884-
text=True,
885-
env=env,
886-
cwd=os.path.dirname(file_path) if file_path else None,
887-
bufsize=1,
888-
)
889-
890923
# Timer pour mettre à jour le statut
891-
start_time = datetime.now()
924+
self._start_time = datetime.now()
892925

893-
# Lire la sortie en temps réel
894-
while True:
895-
line = proc.stdout.readline()
896-
if not line and proc.poll() is not None:
897-
break
898-
if line:
899-
self._log(line.rstrip())
900-
901-
# Lire stderr
902-
stderr = proc.stderr.read()
903-
if stderr:
904-
self._log(f"STDERR:\n{stderr}")
905-
906-
# Récupérer le code de retour
907-
return_code = proc.wait()
908-
end_time = datetime.now()
909-
duration = (end_time - start_time).total_seconds()
910-
911-
self._log("=" * 50)
912-
if return_code == 0:
913-
self._log(
914-
"Compilation successful!"
915-
if self.language == "en"
916-
else "Compilation réussie !"
917-
)
918-
self.statusBar.showMessage(
919-
"Compilation successful!"
920-
if self.language == "en"
921-
else "Compilation terminée !"
922-
)
923-
else:
924-
self._log(
925-
f"Compilation failed with code {return_code}"
926-
if self.language == "en"
927-
else f"Échec de la compilation (code {return_code})"
928-
)
929-
self.statusBar.showMessage(
930-
"Compilation failed"
931-
if self.language == "en"
932-
else "Échec de la compilation"
933-
)
934-
self._log(f"Duration: {duration:.2f}s")
935-
self._log("=" * 50)
926+
# Créer et configurer le thread
927+
working_dir = os.path.dirname(file_path) if file_path else None
928+
self.compilation_thread = CompilationThread(program, args, env, working_dir)
929+
self.compilation_thread.output_ready.connect(self._log)
930+
self.compilation_thread.error_ready.connect(self._on_compilation_error)
931+
self.compilation_thread.finished.connect(self._on_compilation_finished)
932+
self.compilation_thread.start()
936933

937934
else:
938935
self._log(
@@ -943,9 +940,46 @@ def _run_compilation(self):
943940

944941
except Exception as e:
945942
self._log(f"Error: {str(e)}")
946-
finally:
947-
self.progress_bar.setVisible(False)
948-
self.compile_btn.setEnabled(True)
943+
944+
def _on_compilation_error(self, message):
945+
"""Affiche les erreurs de compilation."""
946+
self._log(f"STDERR: {message}")
947+
948+
def _on_compilation_finished(self, return_code):
949+
"""Appelé lorsque la compilation est terminée."""
950+
self._log("=" * 50)
951+
952+
end_time = datetime.now()
953+
duration = (end_time - self._start_time).total_seconds()
954+
955+
if return_code == 0:
956+
self._log(
957+
"Compilation successful!"
958+
if self.language == "en"
959+
else "Compilation réussie !"
960+
)
961+
self.statusBar.showMessage(
962+
"Compilation successful!"
963+
if self.language == "en"
964+
else "Compilation terminée !"
965+
)
966+
else:
967+
self._log(
968+
f"Compilation failed with code {return_code}"
969+
if self.language == "en"
970+
else f"Échec de la compilation (code {return_code})"
971+
)
972+
self.statusBar.showMessage(
973+
"Compilation failed"
974+
if self.language == "en"
975+
else "Échec de la compilation"
976+
)
977+
978+
self._log(f"Duration: {duration:.2f}s")
979+
self._log("=" * 50)
980+
981+
self.progress_bar.setVisible(False)
982+
self.compile_btn.setEnabled(True)
949983

950984
def _dry_run(self):
951985
"""Affiche la commande sans l'exécuter en utilisant l'onglet courant."""
@@ -977,7 +1011,13 @@ def _dry_run(self):
9771011
return
9781012

9791013
try:
980-
engine = create_engine(engine_id)
1014+
# Get the engine instance from registry (has the tab configuration)
1015+
engine = engines_loader.registry.get_instance(engine_id)
1016+
1017+
# If no stored instance, create one (fallback)
1018+
if not engine:
1019+
engine = create_engine(engine_id)
1020+
9811021
result = engine.program_and_args(self, file_path)
9821022

9831023
if result:

0 commit comments

Comments
 (0)