ParamManagerScripts/backend/script_groups/XML Parser to SCL/x3_generate_scl.py

213 lines
8.0 KiB
Python

"""
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" # <-- NUEVO: Nombre del directorio de salida final
# --- 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__":
configs = load_configuration()
working_directory = configs.get("working_directory")
parser = argparse.ArgumentParser(
description=f"Generate final SCL/Markdown file into '{SCL_OUTPUT_DIRNAME}/'."
) # <-- MODIFICADO
parser.add_argument(
"source_xml_filepath", help="Path to the original source XML file."
)
parser.add_argument(
"project_root_dir",
help="Path to the root directory of the XML project structure.",
)
args = parser.parse_args()
source_xml_file = args.source_xml_filepath
project_root_dir = args.project_root_dir
if not os.path.exists(source_xml_file):
print(
f"Advertencia (x3): Archivo XML original no encontrado: '{source_xml_file}'. Se intentará continuar.",
file=sys.stderr,
)
# No salir necesariamente, podríamos tener el JSON procesado
xml_filename_base = os.path.splitext(os.path.basename(source_xml_file))[0]
xml_dir = os.path.dirname(source_xml_file)
parsing_dir = os.path.join(xml_dir, "parsing")
input_json_file = os.path.join(parsing_dir, f"{xml_filename_base}_processed.json")
# <-- MODIFICADO: Calcular directorio de salida final -->
# Siempre será 'scl_output' bajo la raíz del proyecto
final_output_dir = os.path.join(project_root_dir, SCL_OUTPUT_DIRNAME)
# <-- FIN MODIFICADO -->
print(f"(x3) Generando SCL/MD desde: '{os.path.relpath(input_json_file)}'")
print(f"(x3) Directorio de salida final: '{os.path.relpath(final_output_dir)}'")
print(f"(x3) Usando ruta raíz del proyecto: '{project_root_dir}' para buscar UDTs.")
# Asegurar que el directorio de salida final exista ANTES de llamar a la función
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)
if not os.path.exists(input_json_file):
print(
f"Error Fatal (x3): JSON procesado no encontrado: '{input_json_file}'",
file=sys.stderr,
)
sys.exit(1)
else:
try:
# Pasar el directorio de salida FINAL y la ruta raíz
success = generate_scl_or_markdown(
input_json_file, final_output_dir, project_root_dir
) # <-- MODIFICADO
if success:
sys.exit(0)
else:
sys.exit(1) # La función ya imprimió el error
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)