""" LadderToSCL - Conversor de Siemens LAD/FUP XML a SCL Este script es parte de un conjunto de herramientas para convertir proyectos de Siemens LAD/FUP a SCL. """ # ToUpload/x3_generate_scl.py # -*- coding: utf-8 -*- import json import os import re import argparse import sys import traceback script_root = os.path.dirname( os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ) sys.path.append(script_root) from backend.script_utils import load_configuration # --- Importar Generadores Específicos --- try: from generators.generate_scl_db import generate_scl_for_db from generators.generate_scl_code_block import generate_scl_for_code_block from generators.generate_md_udt import generate_udt_markdown from generators.generate_md_tag_table import generate_tag_table_markdown from generators.generator_utils import ( format_variable_name, generate_scl_declarations, ) except ImportError as e: print( f"Error crítico: No se pudieron importar los módulos de 'generators': {e}", file=sys.stderr, ) sys.exit(1) # --- Constantes --- # SCL_OUTPUT_DIRNAME = "scl_output" # <-- Ya no se usa directamente en __main__, se lee de config # --- Modificar generate_scl_or_markdown para usar el nuevo directorio de salida --- def generate_scl_or_markdown( processed_json_filepath, final_output_directory, project_root_dir ): # <-- MODIFICADO: Nombre del argumento """ Genera un archivo SCL o Markdown a partir del JSON procesado, llamando a la función generadora apropiada y escribiendo el archivo en el directorio de salida final (ej. 'scl_output'). Pasa project_root_dir a los generadores relevantes. """ if not os.path.exists(processed_json_filepath): print( f"Error: JSON procesado no encontrado: '{processed_json_filepath}'", file=sys.stderr, ) return False # Indicar fallo print(f"Cargando JSON procesado desde: {processed_json_filepath}") try: with open(processed_json_filepath, "r", encoding="utf-8") as f: data = json.load(f) except Exception as e: print(f"Error al cargar/parsear JSON procesado: {e}", file=sys.stderr) traceback.print_exc(file=sys.stderr) return False # Indicar fallo block_name = data.get("block_name", "UnknownBlock") block_type = data.get("block_type", "Unknown") scl_block_name = format_variable_name(block_name) # Nombre SCL seguro output_content = [] output_extension = ".scl" # Por defecto print( f"Generando salida para: {block_type} '{scl_block_name}' (Original: {block_name})" ) # --- Selección del Generador y Extensión --- generation_function = None func_args = {"data": data} if block_type == "GlobalDB": print(" -> Modo de generación: DATA_BLOCK SCL") generation_function = generate_scl_for_db func_args["project_root_dir"] = project_root_dir output_extension = ".scl" elif block_type in ["FC", "FB", "OB"]: print(f" -> Modo de generación: {block_type} SCL") generation_function = generate_scl_for_code_block func_args["project_root_dir"] = project_root_dir output_extension = ".scl" elif block_type == "PlcUDT": print(" -> Modo de generación: UDT Markdown") generation_function = generate_udt_markdown # generate_udt_markdown no necesita project_root_dir por ahora output_extension = ".md" elif block_type == "PlcTagTable": print(" -> Modo de generación: Tag Table Markdown") generation_function = generate_tag_table_markdown output_extension = ".md" else: print( f"Error: Tipo de bloque desconocido '{block_type}'. No se generará archivo.", file=sys.stderr, ) return False # Indicar fallo # --- Llamar a la función generadora --- if generation_function: try: output_content = generation_function(**func_args) except Exception as gen_e: print( f"Error durante la generación de contenido para {block_type} '{scl_block_name}': {gen_e}", file=sys.stderr, ) traceback.print_exc(file=sys.stderr) return False # Indicar fallo # --- Escritura del Archivo de Salida en el Directorio Final --- output_filename_base = f"{scl_block_name}{output_extension}" # El 'final_output_directory' ya viene calculado desde __main__ output_filepath = os.path.join(final_output_directory, output_filename_base) print( f" -> Escribiendo archivo de salida final en: {os.path.relpath(output_filepath)}" ) try: # Asegurar que el directorio de salida exista (ya debería estar hecho en __main__) os.makedirs(os.path.dirname(output_filepath), exist_ok=True) with open(output_filepath, "w", encoding="utf-8") as f: for line in output_content: f.write(line + "\n") print(f"Generación de {output_extension.upper()} completada.") return True # Indicar éxito except Exception as e: print( f"Error al escribir el archivo final {output_extension.upper()}: {e}", file=sys.stderr, ) traceback.print_exc(file=sys.stderr) return False # Indicar fallo # --- Ejecución (MODIFICADO para usar SCL_OUTPUT_DIRNAME) --- if __name__ == "__main__": # Lógica para ejecución standalone try: import tkinter as tk from tkinter import filedialog except ImportError: print("Error: Tkinter no está instalado. No se puede mostrar el diálogo de archivo.", file=sys.stderr) tk = None input_json_file = "" project_root_dir = "" if tk: root = tk.Tk() root.withdraw() print("Por favor, selecciona el archivo JSON procesado de entrada (generado por x2)...") input_json_file = filedialog.askopenfilename( title="Selecciona el archivo JSON procesado de entrada (_processed.json)", filetypes=[("Processed JSON files", "*_processed.json"), ("JSON files", "*.json"), ("All files", "*.*")] ) if input_json_file: print(f"Archivo JSON procesado seleccionado: {input_json_file}") print("Por favor, selecciona el directorio raíz del proyecto XML (ej. la carpeta 'PLC')...") project_root_dir = filedialog.askdirectory( title="Selecciona el directorio raíz del proyecto XML" ) if project_root_dir: print(f"Directorio raíz del proyecto seleccionado: {project_root_dir}") else: print("No se seleccionó directorio raíz. Saliendo.", file=sys.stderr) else: print("No se seleccionó archivo JSON procesado. Saliendo.", file=sys.stderr) root.destroy() if input_json_file and project_root_dir: # Calcular directorio de salida final # <-- NUEVO: Leer nombre del directorio de salida desde la configuración --> configs = load_configuration() xml_parser_config = configs.get("XML Parser to SCL", {}) cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output") # Leer con default # <-- FIN NUEVO --> final_output_dir = os.path.join(project_root_dir, cfg_scl_output_dirname) # Usar valor leído print(f"(x3 - Standalone) Generando SCL/MD desde: '{os.path.relpath(input_json_file)}'") print(f"(x3 - Standalone) Directorio de salida final: '{os.path.relpath(final_output_dir)}'") print(f"(x3 - Standalone) Usando ruta raíz del proyecto: '{project_root_dir}' para buscar UDTs.") # Asegurar que el directorio de salida final exista try: os.makedirs(final_output_dir, exist_ok=True) except OSError as e: print( f"Error Crítico (x3): No se pudo crear el directorio de salida '{final_output_dir}': {e}", file=sys.stderr, ) # sys.exit(1) # No usar sys.exit success = False # Marcar como fallo para evitar la llamada else: success = True # Marcar como éxito para proceder if success: # Solo intentar si se pudo crear el directorio try: # Llamar a la función principal success = generate_scl_or_markdown( input_json_file, final_output_dir, project_root_dir ) if success: print("\nGeneración de SCL/MD completada exitosamente.") else: # La función generate_scl_or_markdown ya imprime el error print(f"\nError durante la generación desde '{os.path.relpath(input_json_file)}'.", file=sys.stderr) # sys.exit(1) # No usar sys.exit except Exception as e: print(f"Error Crítico no manejado en x3: {e}", file=sys.stderr) traceback.print_exc(file=sys.stderr) # sys.exit(1) # No usar sys.exit else: # Mensajes de cancelación ya impresos si aplica pass