2026-03-09 21:36:27 -05:00
|
|
|
import subprocess
|
|
|
|
|
import os
|
|
|
|
|
import argparse
|
2026-03-10 09:19:00 -05:00
|
|
|
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
|
|
|
|
|
|
2026-03-09 21:36:27 -05:00
|
|
|
|
2026-03-10 07:36:09 -05:00
|
|
|
def CompileFileWithLogFile(metaeditor_path: str, mql5_full_path: str, timeout_sec: int = 60, wineprefix: str = "/home/leoxd/.mt5") -> tuple[bool, str]:
|
2026-03-09 21:52:39 -05:00
|
|
|
print(f"Metaeditor path = {metaeditor_path}")
|
|
|
|
|
print(f"MQL5 path = {mql5_full_path}")
|
|
|
|
|
|
2026-03-10 09:19:00 -05:00
|
|
|
# target dir
|
|
|
|
|
target_dir = os.path.dirname(mql5_full_path)
|
|
|
|
|
|
2026-03-10 07:36:09 -05:00
|
|
|
# env config
|
|
|
|
|
env = os.environ.copy()
|
|
|
|
|
env["WINEPREFIX"] = wineprefix
|
|
|
|
|
env["WINEDEBUG"] = "-all,err+all" # Solo muestra errores críticos
|
|
|
|
|
env["DISPLAY"] = ":99"
|
|
|
|
|
|
2026-03-10 09:19:00 -05:00
|
|
|
# cmd
|
|
|
|
|
|
|
|
|
|
cmd = [
|
|
|
|
|
"wine",
|
|
|
|
|
metaeditor_path,
|
|
|
|
|
"/portable",
|
|
|
|
|
f"/compile:{os.path.basename(mql5_full_path)}", # Sin comillas extra, Wine las manejará mejor así
|
|
|
|
|
"/log"
|
|
|
|
|
]
|
2026-03-10 07:36:09 -05:00
|
|
|
|
2026-03-10 09:19:00 -05:00
|
|
|
print(f"Ejecutando en CWD: {target_dir}")
|
2026-03-10 07:36:09 -05:00
|
|
|
print(f"CMD: {' '.join(cmd)}")
|
|
|
|
|
|
2026-03-09 21:36:27 -05:00
|
|
|
try:
|
|
|
|
|
# Ejecutamos el comando y esperamos (timeout en segundos)
|
2026-03-10 09:19:00 -05:00
|
|
|
result = subprocess.run(cmd, timeout=timeout_sec, capture_output=True, text=True, env=env, cwd=target_dir)
|
2026-03-10 07:36:09 -05:00
|
|
|
|
2026-03-09 22:05:03 -05:00
|
|
|
print(f"STDOUT: {result.stdout}")
|
|
|
|
|
print(f"STDERR: {result.stderr}")
|
2026-03-10 07:36:09 -05:00
|
|
|
|
2026-03-09 21:36:27 -05:00
|
|
|
# Imprimimos el codigo de salida
|
|
|
|
|
print(f"Código de salida: {result.returncode}")
|
2026-03-10 07:36:09 -05:00
|
|
|
|
2026-03-09 21:36:27 -05:00
|
|
|
# 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}")
|
2026-03-10 07:36:09 -05:00
|
|
|
|
|
|
|
|
return result.returncode == 1, log_file # en mql5 es 1 por lo visto
|
|
|
|
|
|
2026-03-09 21:36:27 -05:00
|
|
|
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:
|
2026-03-09 21:44:49 -05:00
|
|
|
if os.path.exists(log_file):
|
2026-03-09 21:36:27 -05:00
|
|
|
# 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:
|
2026-03-10 09:19:00 -05:00
|
|
|
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}")
|