montana/Russian/Site/montana-archive/scripts/build-archives.sh
2026-05-18 18:05:32 +03:00

178 lines
9.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Собирает публичные снапшоты Montana для скачивания.
# Запускается systemd-таймером каждые 30 минут.
# Стратегия: освобождаем место от старых архивов ПЕРЕД сборкой,
# пишем новые напрямую в OUT с суффиксом .new, потом атомарный rename.
set -euo pipefail
REPO_DIR=/var/lib/gitea/data/gitea-repositories/efir369999/montana.git
OUT=/var/www/montana_archive
LOCK=/run/montana-archive.lock
exec 9>"$LOCK"
flock -n 9 || { echo "previous build still running, skip"; exit 0; }
mkdir -p "$OUT"
ts() { date -u +%Y-%m-%dT%H:%M:%SZ; }
log() { echo "[$(ts)] $*"; }
log "=== Сборка архивов Montana ==="
HEAD_SHA=$(GIT_DIR="$REPO_DIR" git rev-parse HEAD)
SHORT_SHA="${HEAD_SHA:0:12}"
log "HEAD = $HEAD_SHA"
DISK_FREE_MB=$(df -m "$OUT" | awk 'NR==2{print $4}')
log "свободно до сборки: ${DISK_FREE_MB}MB"
# чистим старые .new если остались с упавшей предыдущей попытки
rm -f "$OUT"/*.new
# Освобождаем место — удаляем прошлые архивы.
# Окно недоступности: ~3 минуты (пока строятся новые). За это окно
# редиректы /archive/ будут отдавать 404 — это допустимо.
rm -f "$OUT/montana-protocol-latest.tar.gz" \
"$OUT/montana-protocol-latest.zip" \
"$OUT/site-essentials.tar.gz" \
"$OUT/site-latest.tar.gz" \
"$OUT/montana-full.bundle" \
"$OUT/SHA256SUMS"
log "очищено: $(df -m "$OUT" | awk 'NR==2{print $4}')MB свободно"
export GIT_LFS_SKIP_SMUDGE=1
log "→ tar.gz (git archive, без LFS smudge)"
GIT_DIR="$REPO_DIR" git -c filter.lfs.smudge= -c filter.lfs.required=false \
archive --format=tar HEAD \
| gzip -6 > "$OUT/montana-protocol-latest.tar.gz.new"
log "→ zip (git archive)"
GIT_DIR="$REPO_DIR" git -c filter.lfs.smudge= -c filter.lfs.required=false \
archive --format=zip -6 HEAD \
> "$OUT/montana-protocol-latest.zip.new"
log "→ site-essentials (без бинарных ассетов)"
tar -C /var/www -czf "$OUT/site-essentials.tar.gz.new" \
--exclude='*/node_modules' \
--exclude='*/__pycache__' \
--exclude='*.pyc' \
--exclude='*.log' \
--exclude='*.apk' \
--exclude='*.apk.bak*' \
--exclude='*.jpg' \
--exclude='*.jpeg' \
--exclude='*.png' \
--exclude='*.gif' \
--exclude='*.mp4' \
--exclude='*.webm' \
--exclude='*.zip' \
--exclude='*.tar.gz' \
--exclude='*/junona-app/dist' \
--exclude='*/messenger-backend' \
--exclude='montana_quest/vpn/city' \
montana_quest montana_hub_landing || echo "tar warn"
log "→ sha256 + атомарный rename"
( cd "$OUT" && \
sha256sum montana-protocol-latest.tar.gz.new \
montana-protocol-latest.zip.new \
site-essentials.tar.gz.new \
| sed 's/\.new$//' > SHA256SUMS.new && \
mv -f montana-protocol-latest.tar.gz.new montana-protocol-latest.tar.gz && \
mv -f montana-protocol-latest.zip.new montana-protocol-latest.zip && \
mv -f site-essentials.tar.gz.new site-essentials.tar.gz && \
mv -f SHA256SUMS.new SHA256SUMS )
log "→ листинг index.html"
SIZE_TGZ=$(numfmt --to=iec --suffix=B $(stat -c%s "$OUT/montana-protocol-latest.tar.gz"))
SIZE_ZIP=$(numfmt --to=iec --suffix=B $(stat -c%s "$OUT/montana-protocol-latest.zip"))
SIZE_SITE=$(numfmt --to=iec --suffix=B $(stat -c%s "$OUT/site-essentials.tar.gz"))
BUILT="$(ts)"
cat > "$OUT/index.html" <<HTML
<!doctype html>
<html lang="ru"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Архив Монтаны</title>
<meta name="theme-color" content="#0c0a08">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<style>
:root{--bg:#0c0a08;--card:#1a1612;--soft:#14110d;--line:#2a2520;--ink:#e8e0d0;--mute:#8a8175;--gold:#ca9335;--gold-soft:#d9a755;--gold-deep:#8e6824}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--ink);font-family:Inter,-apple-system,system-ui,sans-serif;line-height:1.55;min-height:100vh}
.wrap{max-width:760px;margin:0 auto;padding:2.5rem 1.25rem 4rem}
h1{font-family:ui-serif,Georgia,serif;color:var(--gold);font-size:2rem;font-weight:500;letter-spacing:0.04em;margin-bottom:0.25rem}
.sub{color:var(--mute);font-size:0.9375rem;margin-bottom:2rem}
.file{background:var(--card);border:1px solid var(--line);border-radius:0.75rem;padding:1.125rem 1.25rem;margin-bottom:0.75rem;transition:border-color 0.15s}
.file:hover{border-color:var(--gold-deep)}
.name{font-family:ui-serif,Georgia,serif;color:var(--gold);font-size:1.0625rem;font-weight:500;margin-bottom:0.25rem}
.desc{color:var(--mute);font-size:0.875rem;margin-bottom:0.625rem}
.row{display:flex;flex-wrap:wrap;gap:0.5rem;align-items:center}
.btn{padding:0.5rem 0.875rem;border-radius:0.5rem;background:var(--gold);color:var(--bg);text-decoration:none;font-size:0.8125rem;font-weight:600;letter-spacing:0.01em}
.btn:hover{background:var(--gold-soft)}
.btn.ghost{background:transparent;color:var(--gold);border:1px solid var(--gold-deep)}
.btn.ghost:hover{background:var(--soft)}
.size{color:var(--mute);font-size:0.8125rem;font-family:ui-monospace,Menlo,monospace;margin-left:auto}
.cmd{background:var(--soft);border:1px solid var(--line);border-radius:0.5rem;padding:0.625rem 0.75rem;margin-top:0.625rem;color:var(--gold-soft);font-family:ui-monospace,Menlo,monospace;font-size:0.8125rem;overflow-x:auto;white-space:nowrap}
footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid var(--line);color:var(--mute);font-size:0.8125rem;display:flex;flex-wrap:wrap;justify-content:space-between;gap:0.75rem}
footer a{color:var(--gold-deep);text-decoration:none}
footer a:hover{color:var(--gold)}
.home-link{position:fixed;top:0.75rem;left:0.75rem;display:inline-flex;align-items:center;gap:0.5rem;padding:0.5rem 0.875rem;border:1px solid var(--line);border-radius:0.625rem;background:rgba(20,17,13,0.9);backdrop-filter:blur(8px);color:var(--ink);text-decoration:none;font-size:0.9375rem}
.home-link:hover{border-color:var(--gold-deep)}
.home-logo{color:var(--gold);font-family:ui-serif,Georgia,serif;font-size:1.25rem;line-height:1}
</style></head>
<body>
<a class="home-link" href="/"><span class="home-logo">Ɉ</span> <span>Монтана</span></a>
<div class="wrap">
<h1>Архив Монтаны</h1>
<div class="sub">Открытое хранилище — для людей, ИИ-агентов, индексаторов. Качайте пакетно. Снимки обновляются каждые 30 минут.<br>HEAD <code style="color:var(--gold-soft)">$SHORT_SHA</code> · сборка $BUILT</div>
<div class="file">
<div class="name">montana-protocol-latest.tar.gz</div>
<div class="desc">Текущее состояние main-ветки. Без истории. Бинарные LFS-файлы — указатели (для бинарей — git clone).</div>
<div class="row">
<a class="btn" href="/archive/montana-protocol-latest.tar.gz">Скачать</a>
<a class="btn ghost" href="/archive/SHA256SUMS">SHA256</a>
<span class="size">$SIZE_TGZ</span>
</div>
<div class="cmd">curl -L -o montana.tar.gz https://montana.quest/archive/montana-protocol-latest.tar.gz</div>
</div>
<div class="file">
<div class="name">montana-protocol-latest.zip</div>
<div class="desc">То же самое, но zip — для Windows и систем без gzip.</div>
<div class="row">
<a class="btn" href="/archive/montana-protocol-latest.zip">Скачать</a>
<span class="size">$SIZE_ZIP</span>
</div>
<div class="cmd">curl -L -o montana.zip https://montana.quest/archive/montana-protocol-latest.zip</div>
</div>
<div class="file">
<div class="name">site-essentials.tar.gz</div>
<div class="desc">Шаблоны и тексты публичного сайта (html/css/js/json/svg/xml/txt). Без бинарных ассетов — те качаются напрямую с самих страниц.</div>
<div class="row">
<a class="btn" href="/archive/site-essentials.tar.gz">Скачать</a>
<span class="size">$SIZE_SITE</span>
</div>
<div class="cmd">curl -L -O https://montana.quest/archive/site-essentials.tar.gz</div>
</div>
<div class="file">
<div class="name">Полный git с историей</div>
<div class="desc">Если нужна вся история коммитов и реальные LFS-файлы — клонируйте Хаб напрямую. Анонимный доступ, без логина.</div>
<div class="cmd">git clone https://hub.montana.quest/efir369999/montana.git</div>
<div class="cmd">git clone --depth=1 https://hub.montana.quest/efir369999/montana.git # быстро, без истории</div>
</div>
<footer>
<div>Алик Монтана · Genesis 9.01.2026 · <a href="https://hub.montana.quest/efir369999/montana">источник</a></div>
<div><a href="/llms.txt">llms.txt</a> · <a href="/robots.txt">robots.txt</a> · <a href="/install.sh">подними свой узел</a></div>
</footer>
</div>
</body></html>
HTML
chmod 644 "$OUT"/*
log "=== готово, свободно: $(df -m "$OUT" | awk 'NR==2{print $4}')MB ==="