NixDaemon

NixOS pentest workstation as one flake — IceBreaker's successor
git clone https://git.daemon-sec.xyz/NixDaemon.git
Log | Files | Refs | README

git-site-sync.sh (3791B)


      1 # git-site-sync — keep git.daemon-sec.xyz in step with GitLab.
      2 #
      3 #   git-site-sync            same as `auto`
      4 #   git-site-sync auto       sync only if a mirrored repo's main moved (the timer runs this)
      5 #   git-site-sync now        sync regardless (after editing the theme or build script)
      6 #   git-site-sync status     last sync, what GitLab has now, the timer
      7 #   git-site-sync log        the last runs, from the journal
      8 #
      9 # The repos are whatever ~/git/daemon-sec/script/git-site/repos.json lists
     10 # (NixDaemon, daemon-sec-cheatsheet, daemon-sec-lotl). Checking is one
     11 # `git ls-remote` per repo — a few hundred bytes — so the timer can run
     12 # often; the build and upload (`npm run git-site:sync`, which itself only
     13 # sends changed files) happen only when a head actually moved.
     14 
     15 SITE_REPO=${GIT_SITE_REPO:-$HOME/git/daemon-sec}
     16 CONFIG=$SITE_REPO/script/git-site/repos.json
     17 STATE=${XDG_STATE_HOME:-$HOME/.local/state}/git-site
     18 mkdir -p "$STATE"
     19 
     20 # The npm script calls `nix shell` and `npx`: give a systemd user service the
     21 # system and per-user profiles that an interactive shell would have.
     22 export PATH="$PATH:/run/current-system/sw/bin:/etc/profiles/per-user/$USER/bin"
     23 
     24 die() { echo "git-site-sync: $*" >&2; exit 1; }
     25 [ -f "$CONFIG" ] || die "no $CONFIG (set GIT_SITE_REPO if the site repo moved)"
     26 
     27 # "<name> <commit>" per repo, from GitLab. Fails loudly if any repo cannot be
     28 # read, so a network blip never looks like "nothing changed".
     29 heads() {
     30   local name url sha
     31   jq -r '.repos[] | "\(.name) \(.fetch)"' "$CONFIG" | while read -r name url; do
     32     sha=$(git ls-remote "$url" refs/heads/main | cut -f1) || return 1
     33     [ -n "$sha" ] || { echo "git-site-sync: no main on $url" >&2; return 1; }
     34     printf '%s %s\n' "$name" "$sha"
     35   done
     36 }
     37 
     38 notify() {
     39   command -v notify-send >/dev/null 2>&1 && notify-send -a git-site-sync -u "${2:-normal}" "git.daemon-sec.xyz" "$1" 2>/dev/null || true
     40 }
     41 
     42 sync() {
     43   local new=$1
     44   echo "git-site-sync: syncing…"
     45   if (cd "$SITE_REPO" && npm run -s git-site:sync); then
     46     printf '%s\n' "$new" > "$STATE/heads"
     47     date -Is > "$STATE/last-sync"
     48     echo "git-site-sync: done"
     49   else
     50     notify "Sync failed — git-site-sync log" critical
     51     die "sync failed (git-site-sync log for the details)"
     52   fi
     53 }
     54 
     55 # One run at a time: the timer and a manual `now` must not interleave uploads.
     56 exec 9>"$STATE/lock"
     57 case "${1:-auto}" in
     58   auto | now)
     59     flock -n 9 || { echo "git-site-sync: another sync is running"; exit 0; }
     60     new=$(heads) || die "could not read GitLab (offline?); nothing changed"
     61     if [ "${1:-auto}" = auto ] && [ "$new" = "$(cat "$STATE/heads" 2>/dev/null)" ]; then
     62       echo "git-site-sync: up to date"
     63       exit 0
     64     fi
     65     if [ -f "$STATE/heads" ]; then
     66       diff <(cat "$STATE/heads") <(printf '%s\n' "$new") | sed -n 's/^> /  moved: /p' || true
     67     fi
     68     sync "$new"
     69     ;;
     70   status)
     71     echo "last sync: $(cat "$STATE/last-sync" 2>/dev/null || echo never)"
     72     echo "synced heads:"
     73     sed 's/^/  /' "$STATE/heads" 2>/dev/null || echo "  (none yet)"
     74     if new=$(heads); then
     75       if [ "$new" = "$(cat "$STATE/heads" 2>/dev/null)" ]; then echo "GitLab: no changes since"; else
     76         echo "GitLab now:"; printf '%s\n' "$new" | sed 's/^/  /'; fi
     77     fi
     78     systemctl --user list-timers git-site-sync.timer --no-pager 2>/dev/null | head -2
     79     ;;
     80   log)
     81     journalctl --user -u git-site-sync.service -n "${2:-60}" --no-pager
     82     ;;
     83   -h | --help | help)
     84     echo "usage: git-site-sync [auto|now|status|log [n]]"
     85     echo "  auto    sync if a mirrored repo's main moved (what the timer runs)"
     86     echo "  now     sync regardless"
     87     echo "  status  last sync, GitLab's heads, the timer"
     88     echo "  log     the last runs from the journal"
     89     ;;
     90   *) die "unknown command '$1' (auto, now, status, log)" ;;
     91 esac