Reestructuración modular integral de servicios, reorganización de gestión en docs/ y limpieza profunda del repositorio
This commit is contained in:
Executable
+208
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
# tools/orquestador/dashboard/limpiar.rb
|
||||
# ======================================
|
||||
# Herramienta simple para limpiar hitos duplicados del dashboard P2601
|
||||
# Filosofía: "Menos es más" - herramienta pequeña, específica y reutilizable
|
||||
|
||||
require 'fileutils'
|
||||
|
||||
class DashboardCleaner
|
||||
def initialize(dashboard_path = nil)
|
||||
@dashboard_path = dashboard_path || default_dashboard_path
|
||||
@backup_dir = File.join(File.dirname(@dashboard_path), 'backups')
|
||||
end
|
||||
|
||||
def default_dashboard_path
|
||||
File.expand_path('../../../../dashboard/index.html', __FILE__)
|
||||
end
|
||||
|
||||
def run
|
||||
puts "🧹 LIMPIANDO DASHBOARD P2601"
|
||||
puts "=" * 50
|
||||
|
||||
unless File.exist?(@dashboard_path)
|
||||
puts "❌ Error: No se encuentra el dashboard en #{@dashboard_path}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Crear backup
|
||||
create_backup
|
||||
|
||||
# Leer contenido
|
||||
puts "📖 Leyendo dashboard..."
|
||||
content = File.read(@dashboard_path)
|
||||
original_size = content.length
|
||||
original_lines = content.lines.count
|
||||
|
||||
# Limpiar hitos duplicados
|
||||
puts "🔍 Buscando hitos duplicados..."
|
||||
cleaned_content = remove_duplicate_hitos(content)
|
||||
|
||||
# Verificar cambios
|
||||
if cleaned_content == content
|
||||
puts "✅ No se encontraron hitos duplicados"
|
||||
return true
|
||||
end
|
||||
|
||||
# Guardar cambios
|
||||
puts "💾 Guardando dashboard limpio..."
|
||||
File.write(@dashboard_path, cleaned_content)
|
||||
|
||||
# Mostrar resultados
|
||||
show_results(content, cleaned_content)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_backup
|
||||
FileUtils.mkdir_p(@backup_dir) unless Dir.exist?(@backup_dir)
|
||||
|
||||
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
||||
backup_file = File.join(@backup_dir, "dashboard_clean_#{timestamp}.html")
|
||||
|
||||
puts "💾 Creando backup en: #{backup_file}"
|
||||
FileUtils.cp(@dashboard_path, backup_file)
|
||||
puts "✅ Backup creado"
|
||||
end
|
||||
|
||||
def remove_duplicate_hitos(content)
|
||||
# Patrones para identificar hitos duplicados
|
||||
# Buscamos hitos que comienzan con el comentario de "Hitos adicionales agregados automáticamente"
|
||||
duplicate_pattern = /<!-- Hitos adicionales agregados automáticamente - .*?-->[\s\S]*?(?=<div class="tl-item"|<\/div>\s*<div class="footer">|$)/m
|
||||
|
||||
# Contar ocurrencias
|
||||
matches = content.scan(duplicate_pattern)
|
||||
puts "📊 Encontrados #{matches.size} bloques de hitos duplicados"
|
||||
|
||||
# Eliminar todos los bloques duplicados
|
||||
cleaned = content.gsub(duplicate_pattern, '')
|
||||
|
||||
# También limpiar hitos insertados en lugares incorrectos
|
||||
# Buscar hitos que no están dentro de la sección .timeline
|
||||
timeline_section = extract_timeline_section(cleaned)
|
||||
|
||||
if timeline_section
|
||||
# Mantener solo los hitos dentro de la sección timeline
|
||||
cleaned = restore_proper_structure(cleaned, timeline_section)
|
||||
end
|
||||
|
||||
cleaned
|
||||
end
|
||||
|
||||
def extract_timeline_section(content)
|
||||
# Buscar la sección de timeline
|
||||
timeline_start = content.index('<div class="timeline">')
|
||||
return nil unless timeline_start
|
||||
|
||||
# Encontrar el cierre de la sección timeline
|
||||
# Buscar el cierre del div que contiene la timeline
|
||||
depth = 0
|
||||
timeline_end = timeline_start
|
||||
|
||||
content[timeline_start..-1].chars.each_with_index do |char, i|
|
||||
if content[timeline_start + i, 4] == '<div'
|
||||
depth += 1
|
||||
elsif content[timeline_start + i, 5] == '</div'
|
||||
depth -= 1
|
||||
if depth == 0
|
||||
timeline_end = timeline_start + i + 6 # Incluir '</div>'
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
content[timeline_start...timeline_end]
|
||||
end
|
||||
|
||||
def restore_proper_structure(content, timeline_section)
|
||||
# Reconstruir el contenido manteniendo solo la timeline correcta
|
||||
# Primero, eliminar todas las ocurrencias de hitos fuera de timeline
|
||||
tl_item_pattern = /<div class="tl-item">[\s\S]*?<\/div>\s*<\/div>\s*<\/div>/m
|
||||
|
||||
# Extraer todos los hitos únicos
|
||||
all_hitos = content.scan(tl_item_pattern).uniq
|
||||
|
||||
if all_hitos.any?
|
||||
puts "📋 Encontrados #{all_hitos.size} hitos únicos"
|
||||
|
||||
# Reemplazar la sección timeline completa con una versión limpia
|
||||
new_timeline = <<~HTML
|
||||
<div class="timeline">
|
||||
#{all_hitos.join("\n\n")}
|
||||
</div>
|
||||
HTML
|
||||
|
||||
# Reemplazar la timeline antigua con la nueva
|
||||
content = content.gsub(/<div class="timeline">[\s\S]*?<\/div>\s*<\/div>\s*<\/div>/m, new_timeline)
|
||||
end
|
||||
|
||||
content
|
||||
end
|
||||
|
||||
def show_results(original, cleaned)
|
||||
puts "\n📊 RESULTADOS DE LA LIMPIEZA:"
|
||||
puts " • Líneas originales: #{original.lines.count}"
|
||||
puts " • Líneas limpias: #{cleaned.lines.count}"
|
||||
puts " • Líneas eliminadas: #{original.lines.count - cleaned.lines.count}"
|
||||
puts " • Bytes originales: #{original.length}"
|
||||
puts " • Bytes limpios: #{cleaned.length}"
|
||||
puts " • Bytes ahorrados: #{original.length - cleaned.length}"
|
||||
|
||||
# Contar hitos únicos
|
||||
hitos_count = cleaned.scan(/<div class="tl-item">/).size
|
||||
puts " • Hitos únicos encontrados: #{hitos_count}"
|
||||
|
||||
puts "\n✅ Dashboard limpiado exitosamente"
|
||||
end
|
||||
end
|
||||
|
||||
# Ejecución principal
|
||||
if __FILE__ == $0
|
||||
begin
|
||||
# Parsear argumentos
|
||||
dashboard_path = nil
|
||||
|
||||
ARGV.each_with_index do |arg, i|
|
||||
if arg == '--dashboard' && ARGV[i + 1]
|
||||
dashboard_path = ARGV[i + 1]
|
||||
end
|
||||
end
|
||||
|
||||
cleaner = DashboardCleaner.new(dashboard_path)
|
||||
success = cleaner.run
|
||||
|
||||
if success
|
||||
puts "\n🚀 PRÓXIMOS PASOS:"
|
||||
puts " 1. Verificar dashboard en: https://ns8.frlr.utn.edu.ar/bitacoras/p2601"
|
||||
puts " 2. Usar herramientas de orquestador para agregar hitos correctamente"
|
||||
puts " 3. Revisar backups en: dashboard/backups/"
|
||||
|
||||
puts "\n📅 #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
puts "=" * 50
|
||||
else
|
||||
exit 1
|
||||
end
|
||||
rescue => e
|
||||
puts "❌ Error: #{e.message}"
|
||||
puts e.backtrace if ENV['DEBUG']
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
# Mostrar ayuda si se solicita
|
||||
if ARGV.include?('--help') || ARGV.include?('-h')
|
||||
puts "📖 USO:"
|
||||
puts " #{$0} [--dashboard RUTA]"
|
||||
puts
|
||||
puts "OPCIONES:"
|
||||
puts " --dashboard RUTA - Ruta personalizada al archivo dashboard"
|
||||
puts " --help, -h - Mostrar esta ayuda"
|
||||
puts
|
||||
puts "EJEMPLO:"
|
||||
puts " #{$0} --dashboard /ruta/al/dashboard/index.html"
|
||||
exit 0
|
||||
end
|
||||
Reference in New Issue
Block a user