Ir al contenido
Código en GitHub (se abre en una pestaña nueva)

Documentación · Referencia

El despliegue

Publicar en una carpeta, por FTP, SFTP o en S3.

Versión 0.16

ehundu desplegar [carpeta] [--simular] [--todo]

Compila el proyecto entero, como ehundu compilar, y si no hay errores lo publica en el destino de la sección despliegue de sitio.yml: una carpeta, un servidor FTP o SFTP, o un cubo de S3 o de un servicio compatible. Los campos de cada destino y los secretos están en el §2 del formato.

Con --simular dice qué subiría y qué borraría, sin tocar el destino; sí se conecta, para saber qué hay allí. Un destino carpeta que todavía no existe no se crea. Con --todo lo sube todo aunque no haya cambiado, que es lo que hace falta si alguien ha tocado a mano los ficheros del servidor o si el sitio ha cambiado de dirección.

Qué se sube y qué se borra

Ehundu deja en el destino un fichero, .ehundu.json, con lo que ha subido: la versión del manifiesto, la url del sitio y la ruta, el MD5 y el tamaño de cada fichero, y nada más. Es un JSON así:

{
  "ehundu": 1,
  "url": "https://ejemplo.com",
  "ficheros": {
    "css/estilo.css": { "md5": "…", "tamano": 1234 },
    "index.html": { "md5": "…", "tamano": 5678 }
  }
}

ehundu es la versión del manifiesto (un Ehundu 1.x lee el de cualquier versión anterior, y no lee uno que diga otra cosa), url puede faltar (un despliegue de la 0.1) y las rutas van sin barra al principio, sin .. y ordenadas. Al desplegar lo lee, compara con lo que acaba de compilar y sube solo lo nuevo o lo que ha cambiado. El manifiesto vive en el propio destino para que cualquier máquina que despliegue el sitio vea lo mismo, y para que el motor no tenga que escribir nada en el proyecto fuera de salida/. Se puede leer desde la web, como cualquier fichero del sitio: dice qué ficheros hay, también los que no enlaza ninguna página.

Se borra solo lo que subió Ehundu y ya no se genera. Lo que haya en el destino y no esté en el manifiesto no se toca nunca: el fichero con el que se verifica un dominio, el .well-known de un certificado, un formulario en PHP. La contrapartida es que, la primera vez que se despliega sobre un sitio que ya existía, lo que dejó el sitio anterior se queda allí hasta que alguien lo quite. Las carpetas que se quedan sin nada de Ehundu se intentan quitar; si tienen algo más, se quedan.

Si el destino no tiene manifiesto, se sube todo y no se borra nada. Si lo tiene pero está estropeado, el despliegue se detiene: sin él no se sabe qué se puede borrar. --todo lo rehace.

Un destino de otro sitio

La url del manifiesto dice de qué sitio es el destino. Si no es la de sitio.yml, el despliegue se detiene antes de tocar nada, también al simular. Lo normal es que la ruta esté mal, por ejemplo en un sitio.yml copiado de otro sitio que comparte servidor, y desplegar ahí borraría todo lo que subió el otro sitio.

Si es el mismo sitio con otra dirección (otro dominio, con www o sin él, de http a https), --todo lo confirma: se sube todo, se borra lo que subió Ehundu y ya no se genera, como siempre, y el manifiesto pasa a la dirección nueva. Un aviso lo deja dicho. La comparación es exacta, sin la barra final: cualquier cambio en la url pide confirmarlo.

Un manifiesto sin url, de un despliegue con Ehundu 0.1, se acepta y la gana en el siguiente despliegue.

En qué orden

Primero se suben los ficheros (CSS, imágenes, documentos), después las páginas y al final el sitemap y el feed (también el de cada idioma, eu/feed.xml), para que una página nueva no enlace algo que todavía no está. Los borrados van al final. FTP y SFTP no permiten cambiarlo todo de golpe, así que durante unos segundos conviven lo nuevo y lo viejo; este orden hace que lo que se ve en ese rato funcione.

El manifiesto se guarda cada 50 ficheros o cada 15 segundos, y al terminar. Si un despliegue se corta, el siguiente sigue donde se quedó: lo que ya subió está anotado. Si falla un fichero concreto, se guarda lo hecho hasta ahí antes de detenerse.

Subir por lotes

Desde un proceso web con límite de tiempo, Desplegador::desplegar() admite un presupuesto de $segundos: al agotarse guarda el manifiesto y para, siempre después de al menos un fichero, y el InformeDeDespliegue dice que no está completo ($completo) y cuántos ficheros quedan ($pendientes). La llamada siguiente traza el plan otra vez, ve en el manifiesto lo que ya está subido y sigue por el resto. Con $todo no se reparte, porque sube todo sin mirar el manifiesto. Por eso con $todo el presupuesto se ignora y se sube todo en una sola llamada.

Junto con una compilación repartida en llamadas que ya ha terminado (CompiladorIncrementalEnProceso::avanzar), se pasa su Informe como $compilado y el despliegue no vuelve a compilar en cada llamada.

Cada destino

Carpeta. Una ruta de esta máquina: la raíz de un servidor web local, una carpeta sincronizada, un disco de red. Si es relativa, se cuenta desde el proyecto, y no puede estar dentro de él. Si no existe, se crea al subir el primer fichero, no antes.

FTP. Con la extensión ftp de PHP, que viene con PHP pero puede estar desactivada (en Windows se activa en php.ini con extension=ftp). Usa una sola conexión y el modo pasivo. Si algo falla, lo repite, hasta dos veces, y lo deja dicho en un aviso: si la conexión se ha cortado, vuelve a conectar; si sigue abierta, el servidor ha contestado que no, y eso puede ser pasajero (vsftpd contesta «Failure reading network stream» cuando una subida le llega mal, y deja el fichero a medias), así que lo repite una vez. Algunos servidores FTPS, además, cortan siempre la subida de ciertos tamaños exactos de fichero, sea cual sea su contenido, y ahí repetir no sirve. Por eso, como último recurso, un fichero que no ha subido entero se sube en dos partes: la primera normal y el resto añadido al final (APPE), partiendo por otro punto si tampoco así, y comprobando con SIZE que al final mide lo que tiene que medir (si el servidor no responde a SIZE, valen sus dos respuestas). Queda dicho en un aviso. Los ficheros de 7.000 bytes o menos no se parten. La segunda parte sale de un fichero temporal del sistema, fuera del proyecto, que se borra al terminar, porque la extensión solo sabe mandar APPE desde un fichero. Si tampoco sube en dos partes, es un error. Un fichero que se queda a medias no entra en el manifiesto, así que el siguiente despliegue lo vuelve a subir. Por defecto va cifrado (FTPS explícito); cifrado: no lo desactiva, pero entonces la contraseña viaja a la vista. El cifrado necesita además la extensión openssl, que traen casi todas las instalaciones de PHP. La extensión cifra pero no comprueba el certificado del servidor: protege de quien escucha, no de quien se haga pasar por el servidor. Para eso está SFTP.

SFTP. Con phpseclib, que es PHP puro. Se entra con contraseña (clave) o con una clave privada (clavePrivada, y frase si la lleva). Antes de mandar nada, se comprueba que el servidor es quien dice ser, con la huella de su clave: huella en sitio.yml, tal como la escribe ssh-keygen -l. Si falta, el primer despliegue se detiene y dice cuál es, para que se compruebe con quien administra el servidor y se anote; si no coincide, se detiene.

S3. Cualquier servicio compatible: AWS, Scaleway, Cloudflare R2, Backblaze, Hetzner. Las peticiones se firman en el propio motor, sin el SDK de Amazon, y van por HTTPS con lo que trae PHP (la extensión openssl). El cubo va en el nombre del servidor (cubo.s3.fr-par.scw.cloud), salvo si su nombre lleva puntos o mayúsculas, o si el servidor lleva puerto, es localhost o es una dirección IP: entonces va en la ruta. servidor puede llevar http:// o un puerto, para un servicio local; sin esquema, es HTTPS. Cada fichero sube con su tipo MIME y con su MD5, para que el servicio compruebe que le ha llegado entero. Que el cubo sirva un sitio web se configura en el servicio; el motor no lo toca.

Lo que no hace

Nada después de desplegar: ni avisa a otros servicios ni vacía la caché de una CDN. No hay variables de entorno para los secretos: van en .secretos.yml o los da el programa que incrusta el motor. Y no hay bloqueo: si dos máquinas despliegan el mismo sitio a la vez, el manifiesto puede quedar mal; se arregla con --todo.

Para quien incruste el motor

Desplegador::desplegar() recibe los secretos directamente, sin fichero, e informa de cada fichero subido o borrado según avanza. Decidir qué hacer (PlanDeDespliegue) va aparte de hacerlo (Desplegador::ejecutar()), así que un plan se puede ejecutar por partes, en varias peticiones (ver «Subir por lotes»).

Ver este documento en GitHub (se abre en una pestaña nueva)