hbox-docs/hooks/versiones.py
2026-10-21 19:34:40 -06:00

75 lines
3.1 KiB
Python

"""Versión de los .css y .js propios en cada liga (21-oct-2026).
Sin esto, después de un deploy el navegador sigue usando el tablero.css o el kanban.js anteriores
un buen rato: el nombre del archivo no cambia y el servidor no le pide revisarlo. Pasó el 21-oct: la
página de inicio nueva salió con la ruta a producción sin estilos hasta recargar a la fuerza.
Aquí, al construir, cada liga a un .css o .js que vive en docs/ recibe ?v=<huella del archivo>. Si el
archivo cambió, la dirección cambia y el navegador lo baja otra vez; si no cambió, sigue en caché.
Se aplica al HTML de las páginas de MkDocs (on_post_page) y a las páginas sueltas de docs/
(formularios, cuenta, admin, salir…, en on_post_build). Los archivos de docs/ no se tocan.
Los de Material ya traen su huella en el nombre (main.<huella>.min.css) y no se tocan.
"""
import hashlib
import logging
import os
import posixpath
import re
log = logging.getLogger("mkdocs.hooks.versiones")
_HUELLAS = {}
# href="…x.css" o src="…x.js" sin parámetros (si ya traen ?algo, se respetan)
_LIGA = re.compile(r'(\b(?:href|src)=")([^"#?]+\.(?:css|js))(")')
def on_pre_build(config, **kwargs):
_HUELLAS.clear()
docs = config["docs_dir"]
for raiz, _, archivos in os.walk(docs):
for f in archivos:
if f.endswith((".css", ".js")):
ruta = os.path.join(raiz, f)
with open(ruta, "rb") as fh:
_HUELLAS[os.path.relpath(ruta, docs).replace(os.sep, "/")] = hashlib.sha256(fh.read()).hexdigest()[:10]
def _base(url_pagina):
u = "/" + (url_pagina or "")
return u if u.endswith("/") else posixpath.dirname(u) + "/"
def _marcar(html, base):
def cambia(m):
url = m.group(2)
if url.startswith(("http:", "https:", "//", "data:")):
return m.group(0)
rel = (url if url.startswith("/") else posixpath.normpath(posixpath.join(base, url))).lstrip("/")
huella = _HUELLAS.get(rel)
return m.group(1) + url + "?v=" + huella + m.group(3) if huella else m.group(0)
return _LIGA.sub(cambia, html)
def on_post_page(output, page, config, **kwargs):
return _marcar(output, _base(page.url))
def on_post_build(config, **kwargs):
# páginas sueltas: el HTML de docs/ que MkDocs copia tal cual (formularios, cuenta, redirecciones…)
docs, site, n = config["docs_dir"], config["site_dir"], 0
for raiz, _, archivos in os.walk(docs):
for f in archivos:
if not f.endswith(".html"):
continue
rel = os.path.relpath(os.path.join(raiz, f), docs).replace(os.sep, "/")
destino = os.path.join(site, rel)
if not os.path.isfile(destino):
continue
with open(destino, encoding="utf-8") as fh:
html = fh.read()
nuevo = _marcar(html, _base(rel))
if nuevo != html:
with open(destino, "w", encoding="utf-8") as fh:
fh.write(nuevo)
n += 1
log.info("versiones: %d archivos .css/.js con huella; %d páginas sueltas marcadas", len(_HUELLAS), n)