#!/bin/sh # Clone ou met a jour le depot du catalogue, publie son contenu dans le volume # partage, puis notifie l'application. Boucle jusqu'a l'arret du conteneur. # # La publication passe par un lien symbolique : on ne peut pas renommer le # point de montage lui-meme, mais on peut faire basculer un lien a l'interieur, # et cette bascule est atomique. L'application lit CATALOG_DEST/actuel. set -eu : "${CATALOG_DEST:=/catalogue}" : "${CATALOG_BRANCH:=main}" : "${CATALOG_SUBDIR:=catalog}" : "${SYNC_INTERVAL:=300}" : "${REVISIONS_CONSERVEES:=3}" if [ -z "${CATALOG_REPO:-}" ]; then echo "catalog-sync : CATALOG_REPO non defini. L'application utilisera le catalogue de son image." # On reste en vie sans rien faire : le conteneur ne doit pas boucler en redemarrage. while true; do sleep 3600; done fi TRAVAIL=/tmp/depot TEMOIN=/tmp/derniere-revision-confirmee # Previent l'application, et retient si elle a repondu. Tant que la reponse # n'est pas obtenue, on retente au cycle suivant : au demarrage, catalog-sync # publie souvent avant que web n'ecoute, et sans cette reprise le site # resterait sur le catalogue charge a son lancement. prevenir_application() { revision="$1" [ -n "${RELOAD_URL:-}" ] || return 0 [ "$(cat "$TEMOIN" 2>/dev/null)" = "$revision" ] && return 0 if curl -fsS --max-time 10 -X POST "$RELOAD_URL" >/dev/null 2>&1; then echo "$revision" > "$TEMOIN" echo "catalog-sync : application rechargee ($revision)" else echo "catalog-sync : application injoignable, nouvelle tentative au prochain cycle" >&2 fi } sync_une_fois() { if [ -d "$TRAVAIL/.git" ]; then git -C "$TRAVAIL" fetch --quiet --depth 1 origin "$CATALOG_BRANCH" || return 1 git -C "$TRAVAIL" reset --quiet --hard "origin/$CATALOG_BRANCH" || return 1 else rm -rf "$TRAVAIL" git clone --quiet --depth 1 --branch "$CATALOG_BRANCH" "$CATALOG_REPO" "$TRAVAIL" || return 1 fi SOURCE="$TRAVAIL/$CATALOG_SUBDIR" if [ ! -d "$SOURCE" ]; then echo "catalog-sync : le repertoire $CATALOG_SUBDIR est absent du depot." >&2 return 1 fi REVISION=$(git -C "$TRAVAIL" rev-parse --short HEAD) || return 1 CIBLE="$CATALOG_DEST/rev-$REVISION" if [ -L "$CATALOG_DEST/actuel" ] && [ "$(readlink "$CATALOG_DEST/actuel")" = "$CIBLE" ]; then prevenir_application "$REVISION" # publie, mais l'application l'ignore peut-etre encore return 0 fi rm -rf "$CIBLE.partiel" "$CIBLE" mkdir -p "$CIBLE.partiel" cp -a "$SOURCE"/. "$CIBLE.partiel"/ || return 1 mv "$CIBLE.partiel" "$CIBLE" || return 1 # Bascule atomique du lien, puis menage des anciennes revisions. ln -sfn "$CIBLE" "$CATALOG_DEST/actuel.neuf" mv -f "$CATALOG_DEST/actuel.neuf" "$CATALOG_DEST/actuel" || return 1 ls -1dt "$CATALOG_DEST"/rev-* 2>/dev/null | tail -n +$((REVISIONS_CONSERVEES + 1)) | while read -r vieux; do rm -rf "$vieux" done echo "catalog-sync : catalogue publie ($REVISION)" prevenir_application "$REVISION" } while true; do if ! sync_une_fois; then echo "catalog-sync : echec de la synchronisation, nouvelle tentative dans ${SYNC_INTERVAL}s" >&2 fi sleep "$SYNC_INTERVAL" done