# ToUpload/x5_aggregate.py # -*- coding: utf-8 -*- import os import argparse import sys import glob import traceback # --- 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__": 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)