4141from ..Auto_Command_Builder import compute_for_all
4242from ..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
9448def 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
21492def 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 :
0 commit comments