publish / templates / assemble.sh
662 words
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
#!/usr/bin/env bash
# assemble.sh — assembles and publishes a public source ecosystem at
# https://<HOST>: every repo clonable over plain HTTPS, no git server.
#
#   ./assemble.sh              rebuild + publish every repo
#   ./assemble.sh app1 app2    rebuild only those; the rest stay as last assembled
#   NO_PUBLISH=1 ./assemble.sh …   assemble ROOT/ only, skip pin/publish
#
# TEMPLATE: set HOST and ROOT, fill in repo_for() and the default APPS list.
# Per app it runs the repo's own deploy/publish-repo.sh (which enforces the
# anonymity gate), then lays deploy/.site into ROOT/ as:
#   ROOT/<app>.git/   dumb-HTTP-clonable bare mirror  → https://<HOST>/<app>.git
#   ROOT/<app>/       human page (index.html)         → https://<HOST>/<app>/
# Finally: pin ROOT on IPFS, re-point the HOST IPNS name at the new CID, and
# unpin the previous root (IPFS dedupes unchanged subtrees, so an incremental
# publish costs roughly only the changed repo).
#
# One-time host setup (creates IPNS name + DNS records + TLS cert):
#   ird ipfs ipns create <HOST> --serve
#
# Needs: ird CLI (logged in), jq, rsync. macOS bash 3.2 compatible.
set -euo pipefail
cd "$(dirname "$0")"

HOST=CHANGE-ME.example.ro
ROOT=site-root

repo_for() {
  case "$1" in
    app1) echo "$HOME/path/to/repo1" ;;
    app2) echo "$HOME/path/to/repo2" ;;
    *) echo "unknown app: $1 (known: app1 app2)" >&2; exit 1 ;;
  esac
}

APPS=("$@")
[ ${#APPS[@]} -eq 0 ] && APPS=(app1 app2)

mkdir -p "$ROOT"
for app in "${APPS[@]}"; do
  src=$(repo_for "$app")
  echo "== $app ($src)"
  "$src/deploy/publish-repo.sh"
  rsync -a --delete "$src/deploy/.site/$app.git/" "$ROOT/$app.git/"
  rsync -a --delete --exclude "$app.git" "$src/deploy/.site/" "$ROOT/$app/"
done
cp index.html "$ROOT/index.html"

# ---- releases.json: machine-readable coordinates of every published mirror
# (head, latest tag and its sha), read by the landing pages to fill their
# copy-paste dependency snippets and by scripts/agents directly
releases_json() {
  local gd app head tag tag_sha
  for gd in $ROOT/*.git; do
    [ -d "$gd" ] || continue
    app=$(basename "$gd" .git)
    head=$(git --git-dir="$gd" rev-parse HEAD)
    tag=$(git --git-dir="$gd" describe --tags --abbrev=0 HEAD 2>/dev/null || true)
    tag_sha=""
    [ -n "$tag" ] && tag_sha=$(git --git-dir="$gd" rev-parse "$tag^{commit}")
    jq -n --arg app "$app" --arg host "$HOST" --arg head "$head" \
      --arg tag "$tag" --arg tag_sha "$tag_sha" '
      {($app): {
        git: ("https://" + $host + "/" + $app + ".git"),
        page: ("https://" + $host + "/" + $app + "/"),
        head: $head, head_short: $head[0:7],
        tag: (if $tag == "" then null else $tag end),
        version: (if $tag == "" then null else ($tag | ltrimstr("v")) end),
        tag_sha: (if $tag_sha == "" then null else $tag_sha end),
        tag_sha_short: (if $tag_sha == "" then null else $tag_sha[0:7] end)}}'
  done | jq -s --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
    '{generated_at: $now, apps: (add // {})}' > "$ROOT/releases.json"
}
releases_json

if [ "${NO_PUBLISH:-0}" = "1" ]; then
  echo "assembled $ROOT ($(du -sh "$ROOT" | cut -f1)) — NO_PUBLISH=1, stopping before pin/publish"
  exit 0
fi

PIN_NAME="site:$HOST"
PREV=$(ird ipfs pins --json | jq -r --arg n "$PIN_NAME" \
  '[.pins[]? | select(.name==$n and .state=="pinned")][0].cid // empty')

# stdout carries a cost table + progress lines before the JSON — keep from '{'
CID=$(ird ipfs add "$ROOT" --json --yes | sed -n '/^{/,$p' | jq -r '.root_cid // .pin.cid')
[ -n "$CID" ] && [ "$CID" != "null" ] || { echo "ABORT: could not read CID from ird ipfs add output" >&2; exit 1; }

# `ird ipfs add` names the pin after the folder — re-pin the same CID under
# $PIN_NAME (instant, content already on the node) and drop the folder-named
# entry, so the pin list reads site:<host>
if [ "$CID" != "$PREV" ]; then
  ird ipfs pin "$CID" --name "$PIN_NAME" --yes >/dev/null
fi
TMP_ID=$(ird ipfs pins --json | jq -r --arg c "$CID" --arg n "$ROOT" \
  '[.pins[]? | select(.cid==$c and .name==$n)][0].id // empty')
[ -n "$TMP_ID" ] && ird ipfs pin rm "$TMP_ID" --yes >/dev/null
echo "pinned $PIN_NAME -> $CID"

ird ipfs ipns publish "$HOST" "$CID" --yes

if [ -n "$PREV" ] && [ "$PREV" != "$CID" ]; then
  ird ipfs pin rm "$PREV" --yes && echo "unpinned previous root $PREV"
fi

echo "published: https://$HOST -> $CID"

static mirror of HEAD · about · clone: git clone https://ird.cod-sursa.ro/publish.git