#!/usr/bin/bash set -euo pipefail IFS=$'\n\t' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ -d "${SCRIPT_DIR}/../../.git" ]] || [[ -f "${SCRIPT_DIR}/../../bitacora-cids.json" ]]; then REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" else REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" fi LEDGER_FILE="${REPO_ROOT}/bitacora-cids.json" STAGING_LEDGER="/home/renich/ipfs/staging/bitacora-cids.json" usage() { cat < [OPCIONES] Administrador de la Bitácora Histórica de Instantáneas y CIDs de MxOS. Comandos: list Muestra el historial cronológico de instantáneas y CIDs add [DESCRIP] Registra una nueva instantánea en la bitácora repo [DISTRO] Genera la configuración DNF en archivo de extensión repo show Muestra los detalles completos de una instantánea específica sync Sincroniza el archivo de bitácora hacia el directorio de staging y MFS help Muestra este mensaje de ayuda Ejemplos: $(basename "$0") list $(basename "$0") add bafybeids4fglprd6xrimakgxongtihmdtpdbj7o5x6kewmp2fmiswl53te "Ingesta Fedora Updates" $(basename "$0") repo bafybeids4fglprd6xrimakgxongtihmdtpdbj7o5x6kewmp2fmiswl53te fedora EOF } cmd_list() { if [[ ! -f "${LEDGER_FILE}" ]]; then echo "Error: No se encontró el archivo de bitácora en ${LEDGER_FILE}" >&2 return 1 fi printf "%-22s %-10s %-62s %s\n" "FECHA UTC" "TAMAÑO" "CID RAÍZ" "DESCRIPCIÓN" printf "%-22s %-10s %-62s %s\n" "----------------------" "----------" "--------------------------------------------------------------" "----------------------------------------" jq -r '.instantaneas[] | "\(.fecha)\t\(.tamanio_humano)\t\(.cid)\t\(.descripcion)"' "${LEDGER_FILE}" | \ while IFS=$'\t' read -r fecha tamanio cid desc; do printf "%-22s %-10s %-62s %s\n" "${fecha}" "${tamanio}" "${cid}" "${desc}" done } cmd_add() { local target_cid="${1:-}" local descripcion="${2:-Nueva publicación programada}" if [[ -z "${target_cid}" ]]; then echo "Error: Debe especificar el CID raíz." >&2 usage return 1 fi target_cid="${target_cid#/ipfs/}" local timestamp timestamp="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" local size_bytes=0 local size_human="Desconocido" if command -v ipfs >/dev/null 2>&1; then local mfs_hash mfs_hash="$(ipfs files stat --hash /mxos-root 2>/dev/null || true)" if [[ "${mfs_hash}" == "${target_cid}" ]]; then size_bytes="$(ipfs files stat /mxos-root 2>/dev/null | awk '/CumulativeSize:/ {print $2}')" else local stat_out stat_out="$(timeout 3s ipfs dag stat "/ipfs/${target_cid}" 2>/dev/null || true)" if [[ -n "${stat_out}" ]]; then size_bytes="$(echo "${stat_out}" | awk '/Size:/ {print $2}')" fi fi if [[ -n "${size_bytes}" ]] && [[ "${size_bytes}" =~ ^[0-9]+$ ]] && [[ "${size_bytes}" -gt 0 ]]; then size_human="$(numfmt --to=iec-i --suffix=B "${size_bytes}" 2>/dev/null || echo "${size_bytes} B")" fi fi local tmp_file tmp_file="$(mktemp)" jq --arg cid "${target_cid}" \ --arg ts "${timestamp}" \ --arg desc "${descripcion}" \ --argjson bytes "${size_bytes}" \ --arg human "${size_human}" \ ' .actualizado = $ts | .cid_activo = $cid | .instantaneas = [ { "fecha": $ts, "cid": $cid, "tamanio_bytes": $bytes, "tamanio_humano": $human, "descripcion": $desc, "enlace_gateway": ("https://mirrors.mx-os.mx/ipfs/" + $cid), "enlace_publico": ("https://ipfs.io/ipfs/" + $cid) } ] + [.instantaneas[] | select(.cid != $cid)] ' "${LEDGER_FILE}" > "${tmp_file}" mv "${tmp_file}" "${LEDGER_FILE}" echo "==> Instantánea registrada exitosamente en la bitácora:" echo " Fecha: ${timestamp}" echo " CID: ${target_cid}" echo " Tamaño: ${size_human}" cmd_sync } cmd_repo() { local target_cid="${1:-}" local distro="${2:-fedora}" if [[ -z "${target_cid}" ]]; then target_cid="$(jq -r '.cid_activo' "${LEDGER_FILE}")" fi target_cid="${target_cid#/ipfs/}" case "${distro}" in fedora) cat <&2 return 1 ;; esac } cmd_sync() { if [[ -d "$(dirname "${STAGING_LEDGER}")" ]]; then cp -p "${LEDGER_FILE}" "${STAGING_LEDGER}" echo "==> Copiado ${LEDGER_FILE} -> ${STAGING_LEDGER}" fi if command -v ipfs >/dev/null 2>&1; then ipfs files cp --force "/ipfs/$(ipfs add -Q "${LEDGER_FILE}")" /mxos-root/bitacora-cids.json 2>/dev/null || true fi } main() { local cmd="${1:-list}" shift || true case "${cmd}" in list|ls) cmd_list "$@" ;; add) cmd_add "$@" ;; repo|dnf) cmd_repo "$@" ;; sync) cmd_sync "$@" ;; help|--help|-h) usage ;; *) echo "Comando desconocido: ${cmd}" >&2 usage exit 1 ;; esac } main "$@"