git_infra

Git infra scripts for git.bracken.jp
git clone https://git.bracken.jp/git_infra.git
Log | Files | Refs | LICENSE

gout_gemini (3992B)


      1 #!/bin/sh -e
      2 #
      3 # post-receive.d hook: generate Gemini pages for a repo, plus the repo index.
      4 #
      5 # The twin of gout_html. The post-receive dispatcher feeds the same stdin to
      6 # every hook in post-receive.d, so the two run independently and neither needs
      7 # to know about the other.
      8 #
      9 # Output is served by agate as a virtual host, which is why the root below is
     10 # content/<hostname>/ and why agate must be started with BOTH hostnames:
     11 #   agate_flags="--hostname chris.bracken.jp --hostname git.bracken.jp ..."
     12 #   agate_content="/var/gemini/content"
     13 # agate only resolves the per-hostname subdirectory when given more than one
     14 # --hostname.
     15 #
     16 # Install:
     17 #   /home/git/git_infra/post-receive.d/gout_gemini              (this file, chmod +x)
     18 #   /home/git/<repo>.git/hooks/post-receive.d/gout_gemini -> symlink
     19 
     20 export LC_CTYPE="en_US.UTF-8"
     21 
     22 # agate reads these as a different user (1965) in a different jail, so the
     23 # world bits have to be set.
     24 umask 022
     25 
     26 # Root directory into which gout will write pages.
     27 gmi_root="/var/gemini/content/git.bracken.jp"
     28 
     29 # Hooks are called from the repo directory.
     30 repo_dir=$(pwd)
     31 
     32 # The gout cache file.
     33 # This is an optimisation to avoid regenerating all pages on each push.
     34 #
     35 # It must NOT be shared with gout_html: the cache holds log entries already
     36 # rendered in the output format, so one cache per format.
     37 cachefile="${repo_dir}/.gmicache"
     38 
     39 # The default branch of the repository.
     40 default_branch=$(git symbolic-ref HEAD 2>/dev/null || echo "refs/heads/main")
     41 
     42 # The directory under which all repos are located.
     43 # Repos under this directory will be added to the repo index page.
     44 repos_root=$(dirname "$repo_dir")
     45 
     46 # The user-friendly name of the repository.
     47 repo_name=$(basename "$repo_dir" '.git')
     48 
     49 # Directory into which repo pages will be written.
     50 repo_gmi_dir="${gmi_root}/${repo_name}"
     51 
     52 # Detect --force pushes.
     53 cd "${repo_dir}" || exit 1
     54 force=0
     55 while read -r old new ref; do
     56   # Ignore force pushes to non-default branches.
     57   [ "${ref}" = "${default_branch}" ] || continue
     58 
     59   [ "${old}" = "0000000000000000000000000000000000000000" ] && continue
     60   [ "${new}" = "0000000000000000000000000000000000000000" ] && continue
     61 
     62   hasrevs=$(git rev-list "$old" "^$new" | sed 1q)
     63   if [ -n "$hasrevs" ]; then
     64     echo "[gout] Force push detected on ${ref}: cleaning gemini cache"
     65     force=1
     66     break
     67   fi
     68 done
     69 
     70 # If there was a --force push, delete all existing pages. The lack of a cache
     71 # file will trigger a full rebuild below.
     72 if [ "$force" = "1" ]; then
     73   rm -f "$cachefile"
     74   rm -rf "${repo_gmi_dir}/commit" "${repo_gmi_dir}/file"
     75 fi
     76 
     77 # Build the pages. If $cachefile is not present, a full rebuild is performed.
     78 if [ -e "${repo_dir}/git-daemon-export-ok" ]; then
     79   # Change to the directory where we will output pages.
     80   mkdir -p "$repo_gmi_dir"
     81   cd "$repo_gmi_dir" || exit 1
     82 
     83   # Generate the index page.
     84   # Any repo containing a gout-no-index file will not be indexed.
     85   #
     86   # gout_index -M emits relative links (=> repo/log.gmi), and takes no -m: the
     87   # Mastodon verification link is an HTML-only concept.
     88   echo "[gout] Building gemini repo index"
     89   find "${repos_root}/." -maxdepth 1            \
     90     -type d                                     \
     91     -name "*.git"                               \
     92     -exec test -e "{}/git-daemon-export-ok" \;  \
     93     -exec test ! -e "{}/gout-no-index" \;     \
     94     -print                                      \
     95     | sort -f                                   \
     96     | sed -e 's/"/"\\""/g' -e 's/.*/"&"/'       \
     97     | xargs gout_index -M                       \
     98     > "${gmi_root}/index.gmi"
     99 
    100   # Rebuild the pages for the repo (including for unlisted repos).
    101   echo "[gout] Building gemini pages"
    102   gout -M -c "$cachefile" "$repo_dir"
    103 
    104   # use log as index page: agate looks for index.gmi when a directory is
    105   # requested, and answers "Directory index disabled" if there is none.
    106   echo "[gout] Linking gemini index"
    107   ln -sf log.gmi index.gmi
    108 else
    109   echo "[gout] Not building gemini pages: private repo"
    110 fi