150 lines
6.1 KiB
Python
150 lines
6.1 KiB
Python
"""
|
|
LadderToSCL - Conversor de Siemens LAD/FUP XML a SCL
|
|
|
|
Este script genera documentación en Markdown y SCL a partir de un proyecto XML de Siemens LAD/FUP.
|
|
|
|
"""
|
|
# ToUpload/x5_aggregate.py
|
|
# -*- coding: utf-8 -*-
|
|
import os
|
|
import argparse
|
|
import sys
|
|
import glob
|
|
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
|
|
|
|
# --- Constantes ---
|
|
# Nombre del archivo de salida por defecto (se creará en el directorio raíz del proyecto)
|
|
AGGREGATED_FILENAME = "full_project_representation.md"
|
|
# Directorio donde x4 guarda sus salidas (relativo al directorio raíz del proyecto)
|
|
XREF_OUTPUT_SUBDIR = "xref_output"
|
|
|
|
def aggregate_files(project_root_dir, output_filepath):
|
|
"""
|
|
Busca archivos .scl y .md generados y los agrega en un único archivo Markdown.
|
|
"""
|
|
print(f"--- Iniciando Agregación de Archivos (x5) ---")
|
|
print(f"Directorio Raíz del Proyecto: {project_root_dir}")
|
|
print(f"Archivo de Salida: {output_filepath}")
|
|
|
|
# Patrones para buscar archivos generados
|
|
# Buscamos .scl en cualquier subdirectorio (generados por x3 junto a los XML)
|
|
scl_pattern = os.path.join(project_root_dir, "**", "*.scl")
|
|
# Buscamos .md en cualquier subdirectorio (UDT/TagTable generados por x3)
|
|
md_pattern_general = os.path.join(project_root_dir, "**", "*.md")
|
|
# Buscamos .md específicamente en el directorio de salida de x4
|
|
xref_dir = os.path.join(project_root_dir, XREF_OUTPUT_SUBDIR)
|
|
# xref_pattern = os.path.join(xref_dir, "*.md") # No es necesario, el general los incluye
|
|
|
|
print(f"Buscando archivos SCL con patrón: {scl_pattern}")
|
|
print(f"Buscando archivos MD con patrón: {md_pattern_general}")
|
|
|
|
scl_files = glob.glob(scl_pattern, recursive=True)
|
|
md_files = glob.glob(md_pattern_general, recursive=True)
|
|
|
|
# Filtrar los archivos de salida del propio x5 y los XRef para que no se incluyan dos veces
|
|
# si el patrón general los captura y están en el directorio raíz
|
|
output_filename_base = os.path.basename(output_filepath)
|
|
md_files_filtered = [
|
|
f for f in md_files
|
|
if os.path.basename(f) != output_filename_base # Excluir el archivo de salida
|
|
# No es necesario excluir los XRef explícitamente si están en su subdir
|
|
# and XREF_OUTPUT_SUBDIR not in os.path.relpath(f, project_root_dir).split(os.sep)
|
|
]
|
|
|
|
|
|
all_files = sorted(scl_files + md_files_filtered) # Combinar y ordenar alfabéticamente
|
|
|
|
if not all_files:
|
|
print("Error: No se encontraron archivos .scl o .md para agregar.", file=sys.stderr)
|
|
print("Asegúrate de que los scripts x3 y x4 se ejecutaron correctamente.", file=sys.stderr)
|
|
return False
|
|
|
|
print(f"Se agregarán {len(all_files)} archivos.")
|
|
|
|
try:
|
|
with open(output_filepath, "w", encoding="utf-8") as outfile:
|
|
outfile.write(f"# Representación Completa del Proyecto PLC\n\n")
|
|
outfile.write(f"*(Agregado desde {len(all_files)} archivos)*\n\n")
|
|
|
|
for filepath in all_files:
|
|
relative_path = os.path.relpath(filepath, project_root_dir)
|
|
print(f" Agregando: {relative_path}")
|
|
|
|
# Añadir separador y encabezado de archivo
|
|
outfile.write(f"\n---\n")
|
|
outfile.write(f"## Archivo: `{relative_path.replace(os.sep, '/')}`\n\n")
|
|
|
|
try:
|
|
with open(filepath, "r", encoding="utf-8") as infile:
|
|
content = infile.read()
|
|
|
|
# Determinar si es SCL para envolverlo en bloque de código
|
|
if filepath.lower().endswith(".scl"):
|
|
outfile.write("```pascal\n")
|
|
outfile.write(content)
|
|
outfile.write("\n```\n")
|
|
else: # Asumir que es Markdown y escribir directamente
|
|
outfile.write(content)
|
|
outfile.write("\n") # Asegurar nueva línea al final
|
|
|
|
except Exception as read_err:
|
|
print(f" Error al leer {relative_path}: {read_err}", file=sys.stderr)
|
|
outfile.write(f"```\nERROR AL LEER ARCHIVO: {relative_path}\n{read_err}\n```\n")
|
|
|
|
print(f"\nAgregación completada. Archivo guardado en: {output_filepath}")
|
|
return True
|
|
|
|
except IOError as write_err:
|
|
print(f"Error Crítico: No se pudo escribir el archivo agregado '{output_filepath}'. Error: {write_err}", file=sys.stderr)
|
|
return False
|
|
except Exception as e:
|
|
print(f"Error Crítico inesperado durante la agregación: {e}", file=sys.stderr)
|
|
traceback.print_exc(file=sys.stderr)
|
|
return False
|
|
|
|
# --- Punto de Entrada ---
|
|
if __name__ == "__main__":
|
|
configs = load_configuration()
|
|
working_directory = configs.get("working_directory")
|
|
parser = argparse.ArgumentParser(
|
|
description="Agrega archivos .scl y .md generados en un único archivo Markdown."
|
|
)
|
|
parser.add_argument(
|
|
"project_root_dir",
|
|
help="Ruta al directorio raíz del proyecto XML (donde se buscarán los archivos generados)."
|
|
)
|
|
parser.add_argument(
|
|
"-o", "--output",
|
|
help=f"Ruta completa para el archivo Markdown agregado (por defecto: '{AGGREGATED_FILENAME}' en project_root_dir)."
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Validar directorio de entrada
|
|
if not os.path.isdir(args.project_root_dir):
|
|
print(f"Error: El directorio del proyecto no existe: '{args.project_root_dir}'", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Determinar ruta de salida
|
|
output_file = args.output
|
|
if not output_file:
|
|
output_file = os.path.join(args.project_root_dir, AGGREGATED_FILENAME)
|
|
else:
|
|
# Asegurarse de que el directorio de salida exista si se especifica una ruta completa
|
|
output_dir = os.path.dirname(output_file)
|
|
if output_dir and not os.path.exists(output_dir):
|
|
os.makedirs(output_dir)
|
|
|
|
|
|
# Llamar a la función principal
|
|
success = aggregate_files(args.project_root_dir, output_file)
|
|
|
|
if success:
|
|
sys.exit(0)
|
|
else:
|
|
sys.exit(1) |