import subprocess import os import argparse import shutil def move_to_experts(mql5_full_path: str, mql5_root: str) -> str: # Lista de carpetas base permitidas bases : list[str] = ["Experts", "Scripts", "Shared Projects", "Libraries", "Includes", "Services"] # Convertir paths a formato absoluto normalizado mql5_full_path = os.path.normpath(mql5_full_path) # Buscar la carpeta base en el path parts = mql5_full_path.split(os.sep) base_idx = -1 for i, part in enumerate(parts): if part in bases: base_idx = i break # si es esperts entonces retonarmos tal cual no hace falta.. hacer nada if parts[base_idx] == "Experts": return mql5_full_path # Si no estamos en una carpeta "base", retonrans la ubicaicon actual if base_idx == -1: print("No se detectó una carpeta base valida. Abortando move.") return mql5_full_path # Extraer sub-ruta: desde la carpeta base hasta el archivo (sin el archivo) # Ejemplo: Si path es /MQL5/Shared Projects/TbpWrraper/Workflows/EA.mq5 # base_idx apunta a 'Shared Projects', queremos ['Shared Projects', 'TbpWrraper', 'Workflows'] sub_path_parts = parts[base_idx:-1] # onstruir ruta destino en Experts # Resultado: /MQL5/Experts/Shared Projects/TbpWrraper/Workflows/ experts_dir = os.path.join(mql5_root, "Experts", *sub_path_parts) # Crear directorios y hacer el link if not os.path.exists(experts_dir): os.makedirs(experts_dir) source_ex5 = os.path.splitext(mql5_full_path)[0] + ".ex5" dest_ex5 = os.path.join(experts_dir, os.path.basename(source_ex5)) if os.path.exists(dest_ex5): os.remove(dest_ex5) shutil.move(source_ex5, dest_ex5) return dest_ex5 def CompileFileWithLogFile(metaeditor_path: str, mql5_full_path: str, timeout_sec: int = 60, wineprefix: str = "/home/leoxd/.mt5") -> tuple[bool, str]: print(f"Metaeditor path = {metaeditor_path}") print(f"MQL5 path = {mql5_full_path}") # target dir target_dir = os.path.dirname(mql5_full_path) # env config env = os.environ.copy() env["WINEPREFIX"] = wineprefix env["WINEDEBUG"] = "-all,err+all" # Solo muestra errores críticos env["DISPLAY"] = ":99" # cmd cmd = [ "wine", metaeditor_path, "/portable", f"/compile:{os.path.basename(mql5_full_path)}", # Sin comillas extra, Wine las manejará mejor así "/log" ] print(f"Ejecutando en CWD: {target_dir}") print(f"CMD: {' '.join(cmd)}") try: # Ejecutamos el comando y esperamos (timeout en segundos) result = subprocess.run(cmd, timeout=timeout_sec, capture_output=True, text=True, env=env, cwd=target_dir) print(f"STDOUT: {result.stdout}") print(f"STDERR: {result.stderr}") # Imprimimos el codigo de salida print(f"Código de salida: {result.returncode}") # Verifica si el archivo log se creó (opcional, para mayor validación) log_file = os.path.splitext(mql5_full_path)[0] + ".log" if os.path.exists(log_file): print(f"Log generado: {log_file}") return result.returncode == 1, log_file # en mql5 es 1 por lo visto except subprocess.TimeoutExpired: print("Error: La compilación excedió el tiempo límite.") return False, "" except Exception as e: print(f"Error al ejecutar MetaEditor: {str(e)}") return False, "" if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--metaeditor_exe_path", type=str, required=True) # path al metaeditor.exe parser.add_argument("--executor_mq5_full_path", type=str, required=True) # path al ea ejecutor parser.add_argument("--timeout_sec", type=int, default=60) # timeout de espera args = parser.parse_args() res, log_file = CompileFileWithLogFile(args.metaeditor_exe_path, args.executor_mq5_full_path, args.timeout_sec) if not res: if os.path.exists(log_file): # Abrir archivo e imprimir en consola su contenido with open(log_file, "r", encoding="utf-16") as f: print(f.read()) else: print("Error no se genero un archivo log") else: print("Exito al compilar el ea ejecutor") mt5_dir = os.path.dirname(args.metaeditor_exe_path) mql5_root = os.path.join(mt5_dir, "MQL5") dest = move_to_experts(args.executor_mq5_full_path, mql5_root) print(f"Ex5 movido a en: {dest}")