Skip to content

Commit f72744b

Browse files
author
PyCompiler ARK++
committed
perfectionnement des systems
1 parent b6fada9 commit f72744b

7 files changed

Lines changed: 612 additions & 727 deletions

File tree

Core/Compiler/mainprocess.py

Lines changed: 43 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -41,54 +41,8 @@
4141
from ..Auto_Command_Builder import compute_for_all
4242
from ..preferences import MAX_PARALLEL
4343

44-
# Wrapper ACASL inspiré du modèle BCASL: garantit arrêt propre et callback sur thread GUI
45-
from PySide6.QtCore import QTimer as _QTimer
44+
# ACASL support removed (obsolete)
4645

47-
def safe_run_acasl_async(self, artifacts: list[str], finished_cb=None) -> None:
48-
try:
49-
from acasl import run_post_compile_async as _acasl_run, ensure_acasl_thread_stopped as _acasl_stop
50-
except Exception:
51-
# Si ACASL indisponible, renvoyer un rapport 'disabled'
52-
try:
53-
if callable(finished_cb):
54-
_QTimer.singleShot(0, lambda: finished_cb({"status": "disabled", "plugins": []}))
55-
except Exception:
56-
pass
57-
return
58-
# Arrêt propre d'un éventuel ACASL en cours
59-
try:
60-
_acasl_stop(self)
61-
except Exception:
62-
pass
63-
# Ne pas lancer si l'UI est en fermeture
64-
try:
65-
if hasattr(self, "_closing") and bool(getattr(self, "_closing")):
66-
if callable(finished_cb):
67-
_QTimer.singleShot(0, lambda: finished_cb({"status": "cancelled"}))
68-
return
69-
except Exception:
70-
pass
71-
# Wrapper qui garantit l'exécution du callback dans le thread GUI
72-
def _finish_on_gui(rep):
73-
try:
74-
if callable(finished_cb):
75-
_QTimer.singleShot(0, lambda r=rep: finished_cb(r))
76-
except Exception:
77-
pass
78-
try:
79-
_acasl_run(self, list(artifacts or []), finished_cb=_finish_on_gui)
80-
except Exception as e:
81-
# Journaliser et renvoyer une erreur non bloquante
82-
try:
83-
if hasattr(self, "log") and self.log:
84-
self.log.append(f"❌ ACASL: échec de lancement: {e}")
85-
except Exception:
86-
pass
87-
try:
88-
if callable(finished_cb):
89-
_QTimer.singleShot(0, lambda: finished_cb({"status": "error", "error": str(e)}))
90-
except Exception:
91-
pass
9246

9347

9448
def try_start_processes(self):
@@ -105,110 +59,34 @@ def try_start_processes(self):
10559
self.progress.setRange(0, 1)
10660
self.progress.setValue(1)
10761
from PySide6.QtWidgets import QApplication
108-
10962
QApplication.processEvents()
11063
self.log.append("✔️ Toutes les compilations sont terminées.\n")
111-
# Collecter les artefacts dès maintenant
112-
artifacts = []
64+
# Exécuter immédiatement les hooks de succès des moteurs et restaurer l'UI
11365
try:
114-
import os as _os
115-
116-
ws = self.workspace_dir or os.getcwd()
117-
for d in ("dist", "build"):
118-
dp = os.path.join(ws, d)
119-
if os.path.isdir(dp):
120-
for root, _dirs, files in os.walk(dp):
121-
for f in files:
122-
artifacts.append(os.path.join(root, f))
123-
except Exception:
124-
pass
125-
# Décider si ACASL doit s'exécuter; sinon restaurer l'UI immédiatement
126-
try:
127-
import os as _os
128-
129-
no_hooks = True
130-
except Exception:
131-
no_hooks = False
132-
# ACASL removed: execute engine success hooks immediately and restore UI
133-
if True:
134-
try:
135-
hooks = getattr(self, "_pending_engine_success_hooks", [])
136-
for (eng, fpath) in hooks:
137-
try:
138-
eng.on_success(self, fpath)
139-
except Exception:
140-
try:
141-
self.log.append(
142-
f"⚠️ on_success du moteur '{getattr(eng, 'id', '?')}' a échoué."
143-
)
144-
except Exception:
145-
pass
146-
except Exception:
147-
pass
148-
finally:
66+
hooks = getattr(self, "_pending_engine_success_hooks", [])
67+
for (eng, fpath) in hooks:
14968
try:
150-
if hasattr(self, "_pending_engine_success_hooks"):
151-
self._pending_engine_success_hooks.clear()
69+
eng.on_success(self, fpath)
15270
except Exception:
153-
pass
154-
if hasattr(self, "compiler_tabs") and self.compiler_tabs:
155-
self.compiler_tabs.setEnabled(True)
156-
self.set_controls_enabled(True)
157-
self.save_preferences()
158-
return
159-
# Laisser l'UI désactivée jusqu'à la fin d'ACASL, puis restaurer dans le callback
160-
try:
161-
from acasl import run_post_compile_async
162-
163-
def _after_acasl(_rep):
164-
# Exécuter maintenant tous les hooks on_success engrangés
165-
try:
166-
hooks = getattr(self, "_pending_engine_success_hooks", [])
167-
for (eng, fpath) in hooks:
168-
try:
169-
eng.on_success(self, fpath)
170-
except Exception:
171-
try:
172-
self.log.append(
173-
f"⚠️ on_success du moteur '{getattr(eng, 'id', '?')}' a échoué."
174-
)
175-
except Exception:
176-
pass
177-
except Exception:
178-
pass
179-
finally:
180-
try:
181-
if hasattr(self, "_pending_engine_success_hooks"):
182-
self._pending_engine_success_hooks.clear()
183-
except Exception:
184-
pass
185-
# Restaurer l'UI
186-
try:
187-
if hasattr(self, "compiler_tabs") and self.compiler_tabs:
188-
self.compiler_tabs.setEnabled(True)
189-
except Exception:
190-
pass
19171
try:
192-
self.set_controls_enabled(True)
72+
self.log.append(
73+
f"⚠️ on_success du moteur '{getattr(eng, 'id', '?')}' a échoué."
74+
)
19375
except Exception:
19476
pass
195-
try:
196-
self.save_preferences()
197-
except Exception:
198-
pass
199-
200-
QTimer.singleShot(
201-
0,
202-
lambda a=list(artifacts): safe_run_acasl_async(
203-
self, a, finished_cb=_after_acasl
204-
),
205-
)
77+
except Exception:
78+
pass
79+
finally:
80+
try:
81+
if hasattr(self, "_pending_engine_success_hooks"):
82+
self._pending_engine_success_hooks.clear()
20683
except Exception:
207-
# En cas d'échec de démarrage d'ACASL, restaurer l'UI immédiatement
208-
if hasattr(self, "compiler_tabs") and self.compiler_tabs:
209-
self.compiler_tabs.setEnabled(True)
210-
self.set_controls_enabled(True)
211-
self.save_preferences()
84+
pass
85+
if hasattr(self, "compiler_tabs") and self.compiler_tabs:
86+
self.compiler_tabs.setEnabled(True)
87+
self.set_controls_enabled(True)
88+
self.save_preferences()
89+
return
21290

21391

21492
def start_compilation_process(self, file):
@@ -302,7 +180,26 @@ def start_compilation_process(self, file):
302180
process._cancel_file = cancel_file
303181
process.readyReadStandardOutput.connect(lambda p=process: self.handle_stdout(p))
304182
process.readyReadStandardError.connect(lambda p=process: self.handle_stderr(p))
305-
process.finished.connect(lambda ec, es, p=process: self.handle_finished(p, ec, es))
183+
184+
# Capture stderr data before process deletion to avoid accessing deleted C++ object
185+
def _on_finished(ec, es, p=process):
186+
try:
187+
# Save stderr data before process is deleted
188+
p._final_stderr = p.readAllStandardError().data().decode()
189+
except Exception:
190+
p._final_stderr = ""
191+
try:
192+
self.handle_finished(p, ec, es)
193+
except Exception:
194+
pass
195+
finally:
196+
# Schedule deletion after handle_finished completes
197+
try:
198+
p.deleteLater()
199+
except Exception:
200+
pass
201+
202+
process.finished.connect(_on_finished)
306203
self.processes.append(process)
307204
self.current_compiling.add(file)
308205
# Optional: update dependent UI states
@@ -384,8 +281,6 @@ def _cancel_timer(_ec, _es, timer=t):
384281
pass
385282

386283
process.finished.connect(_cancel_timer)
387-
# Ensure QProcess object is deleted later to avoid dangling C++ objects
388-
process.finished.connect(lambda _ec, _es, p=process: p.deleteLater())
389284
except Exception:
390285
pass
391286
process.start()
@@ -790,7 +685,8 @@ def handle_finished(self, process, exit_code, exit_status):
790685
pass
791686
else:
792687
# Ajout d'un affichage détaillé pour les erreurs inattendues
793-
error_details = process.readAllStandardError().data().decode()
688+
# Use saved stderr data to avoid accessing deleted C++ object
689+
error_details = getattr(process, "_final_stderr", "")
794690
self.log.append(
795691
f"<span style='color:red;'>❌ La compilation de {file_basename} ({file}) a échoué (code {exit_code}).</span>\n"
796692
)
@@ -989,12 +885,7 @@ def cancel_all_compilations(self):
989885
self.processes.remove(process)
990886
except ValueError:
991887
pass
992-
# Last resort: stop ACASL thread and nuke any remaining descendants of our GUI process
993-
try:
994-
# ACASL removed: nothing to stop here
995-
pass
996-
except Exception:
997-
pass
888+
# ACASL removed: no post-compile thread to stop
998889
try:
999890
_kill_all_descendants(timeout=1.0, log=self.log.append)
1000891
except Exception:

Core/MainWindow.py

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ def __init__(self):
184184

185185
self.load_preferences()
186186
self.init_ui()
187+
188+
187189
# Détection langue système si préférence = "System"
188190
import locale
189191

@@ -1547,17 +1549,9 @@ def _on_result(res):
15471549
# Registry-based propagation to engine instances
15481550
try:
15491551
import Core.engines_loader as engines_loader
1550-
15511552
engines_loader.registry.apply_translations(self, tr)
15521553
except Exception:
15531554
pass
1554-
# Propagate translations to all BCASL plugins
1555-
try:
1556-
import bcasl.Loader as bcasl_loader
1557-
1558-
bcasl_loader.apply_translations(self, tr)
1559-
except Exception:
1560-
pass
15611555
except Exception:
15621556
pass
15631557
# Update markers
@@ -1717,6 +1711,7 @@ def _safe_log(self, text):
17171711
except Exception:
17181712
pass
17191713

1714+
17201715
def _has_active_background_tasks(self):
17211716
# Compilation en cours
17221717
if self.processes:
@@ -1728,6 +1723,13 @@ def _has_active_background_tasks(self):
17281723
and self.venv_manager.has_active_tasks()
17291724
):
17301725
return True
1726+
# BCASL (pré-compilation) en cours
1727+
try:
1728+
bcasl_thread = getattr(self, "_bcasl_thread", None)
1729+
if bcasl_thread is not None and bcasl_thread.is_alive():
1730+
return True
1731+
except Exception:
1732+
pass
17311733
return False
17321734

17331735
def _terminate_background_tasks(self):
@@ -1745,28 +1747,60 @@ def closeEvent(self, event):
17451747
details.append("compilation")
17461748
if hasattr(self, "venv_manager") and self.venv_manager:
17471749
details.extend(self.venv_manager.get_active_task_labels("Français"))
1748-
if getattr(self, "current_language", "Français") == "English":
1750+
1751+
is_english = getattr(self, "current_language", "Français") == "English"
1752+
1753+
if is_english:
17491754
mapping = {
17501755
"compilation": "build",
17511756
"création du venv": "venv creation",
17521757
"installation des dépendances": "dependencies installation",
17531758
"vérification/installation du venv": "venv check/installation",
17541759
}
17551760
details_disp = [mapping.get(d, d) for d in details]
1756-
msg = "A process is running"
1761+
1762+
# Construire le message détaillé
1763+
title = "⚠️ Process Running"
1764+
msg = "A process is currently running:\n\n"
17571765
if details_disp:
1758-
msg += " (" + ", ".join(details_disp) + ")"
1759-
msg += ". Do you really want to stop and quit?"
1760-
title = "Process running"
1766+
for detail in details_disp:
1767+
msg += f" • {detail}\n"
1768+
msg += "\n"
1769+
msg += "If you quit now, the process will be stopped and any unsaved work will be lost.\n\n"
1770+
msg += "Do you really want to quit?"
1771+
1772+
yes_text = "Yes, Quit"
1773+
no_text = "No, Continue"
17611774
else:
1762-
msg = "Un processus est en cours"
1763-
if details:
1764-
msg += " (" + ", ".join(details) + ")"
1765-
msg += ". Voulez-vous vraiment arrêter et quitter ?"
1766-
title = "Processus en cours"
1767-
reply = QMessageBox.question(
1768-
self, title, msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No
1769-
)
1775+
details_disp = details
1776+
1777+
# Construire le message détaillé
1778+
title = "⚠️ Processus en cours"
1779+
msg = "Un processus est actuellement en cours :\n\n"
1780+
if details_disp:
1781+
for detail in details_disp:
1782+
msg += f" • {detail}\n"
1783+
msg += "\n"
1784+
msg += "Si vous quittez maintenant, le processus sera arrêté et tout travail non sauvegardé sera perdu.\n\n"
1785+
msg += "Voulez-vous vraiment quitter ?"
1786+
1787+
yes_text = "Oui, Quitter"
1788+
no_text = "Non, Continuer"
1789+
1790+
# Créer la boîte de dialogue avec des boutons personnalisés
1791+
msgbox = QMessageBox(self)
1792+
msgbox.setWindowTitle(title)
1793+
msgbox.setText(msg)
1794+
msgbox.setIcon(QMessageBox.Warning)
1795+
msgbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
1796+
msgbox.setDefaultButton(QMessageBox.No)
1797+
1798+
# Personnaliser les textes des boutons
1799+
msgbox.button(QMessageBox.Yes).setText(yes_text)
1800+
msgbox.button(QMessageBox.No).setText(no_text)
1801+
1802+
reply = msgbox.exec()
1803+
17701804
if reply == QMessageBox.Yes:
17711805
self._closing = True
17721806
# Annule les compilations en cours si nécessaire

0 commit comments

Comments
 (0)