git_infra

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

grm (8617B)


      1 #!/bin/sh
      2 # grm: git repo manager for self-hosted git servers
      3 
      4 # This is a customised version of grm.
      5 #
      6 # The original version can be obtained from:
      7 # https://sink.krj.st/grm
      8 #
      9 # Copyright 2020 by krasjet.
     10 # License: https://sink.krj.st/grm/file/LICENSE
     11 
     12 
     13 #---------------+----------+-----------------#
     14 #               |  config  |                 #
     15 #               +----------+                 #
     16 
     17 # root directory of git repositories
     18 GRM_REPOS_ROOT="/home/git"
     19 
     20 # default owner
     21 GRM_OWNER="Chris Bracken"
     22 
     23 # default url prefix (without ending slash)
     24 GRM_URL_PREFIX="https://git.bracken.jp"
     25 
     26 # Add Mastodon verification URL to index header.
     27 ME_URL="https://bsd.network/@cbracken"
     28 
     29 # path of the post-receive hooks for gitout
     30 GRM_POSTRECV_HOOK="/home/git/git_infra/post-receive"
     31 GRM_POSTRECV_HOOKS_DIR="/home/git/git_infra/post-receive.d"
     32 
     33 # root directory of gitout web pages
     34 GITOUT_WEB_ROOT="/usr/local/www/git.bracken.jp"
     35 
     36 #                                            #
     37 #                                            #
     38 #--------------------------------------------#
     39 
     40 # for gitout
     41 export LC_CTYPE="en_US.UTF-8"
     42 
     43 prog_name="${0##*/}"
     44 repos_root=${GRM_REPOS_ROOT:-/home/git}
     45 web_root=${GITOUT_WEB_ROOT:-/srv/git}
     46 
     47 recompile_repo() {
     48   repo_dir="${repos_root}/${1}.git"
     49   repo_web_dir="${web_root}/${repo_name}"
     50   cachefile="${repo_dir}/.htmlcache"
     51 
     52   [ -d "$repo_dir" ] || { echo "[$1] repo not found"; return 1; }
     53 
     54   if [ -e "$repo_dir/git-daemon-export-ok" ]; then
     55     echo "[$1] recompiling gitout pages..."
     56     mkdir -p "$repo_web_dir"
     57     cd "${repo_web_dir:?}"             && \
     58     rm -f "$cachefile"                 && \
     59     rm -rf "commit" "file"             && \
     60     gitout -c "$cachefile" "$repo_dir" && \
     61     ln -sf log.html index.html         && \
     62     ln -sf ../logo.png logo.png        && \
     63     ln -sf ../style.css style.css      && \
     64     ln -sf ../favicon.png favicon.png  && \
     65     echo "[$1] done!"
     66   else
     67     echo "[$1] Not recompiling gitout pages: private repo"
     68   fi
     69 }
     70 
     71 rebuild_index() {
     72   echo "[index] rebuilding index..."
     73   mkdir -p "${web_root}" || return 1;
     74   # 1. find all directories in $repos_root ending with .git
     75   # 2. filter all the public repos (with git-daemon-export-ok)
     76   # 3. exclude any repo marked with gitout-no-index
     77   # 4. sort the result
     78   # 5. hack for posix compatibility
     79   # 6. run gitout_index on the result
     80   # 7. export result to index.html
     81   find "${repos_root}/." ! -name . -prune     \
     82     -type d -name "*.git"                     \
     83     -exec test -e "{}/git-daemon-export-ok" \;\
     84     -exec test ! -e "{}/gitout-no-index" \;   \
     85     -print                                    \
     86     | sort -f                                 \
     87     | sed -e 's/"/"\\""/g' -e 's/.*/"&"/'     \
     88     | xargs gitout_index -m "${ME_URL}"       \
     89     > "${web_root}/index.html" && \
     90   echo "[index] done!"
     91 }
     92 
     93 RED="\033[91m"
     94 GREEN="\033[92m"
     95 YELLOW="\033[93m"
     96 BLUE="\033[94m"
     97 RESET="\033[0m"
     98 
     99 grm_new() {
    100   set -e
    101   default_owner=${GRM_OWNER:-$(logname)}
    102   url_prefix=${GRM_URL_PREFIX:-git://$(hostname -f)}
    103   default_desc="a work in progress"
    104 
    105   printf "%b\n> " "${BLUE}repo name (without trailing .git)${RESET}"
    106   read -r repo_name
    107   [ -z "$repo_name" ] && \
    108     { echo "no repo name given, exiting..."; exit 1; }
    109 
    110   # now we have the complete path of the repo
    111   repo_path="$repos_root/${repo_name}.git"
    112   [ -e "$repo_path" ] && \
    113     { echo "repository already exists"; exit 1; }
    114 
    115   printf "%b\n> " "${YELLOW}visibility:
    116   1) public\n  2) private\n  3) unlisted (hide from index)
    117 ${BLUE}enter index [default: ${GREEN}1${BLUE}]${RESET}"
    118   read -r visibility
    119 
    120   case $visibility in
    121      1|public) exported=1 ;;
    122      2|private) hidden=1 ;;
    123      3|unlisted) exported=1; hidden=1 ;;
    124      *) printf "%b\n" "${YELLOW}visibility defaults to ${GREEN}public${RESET}"
    125         exported=1 ;;
    126   esac
    127 
    128   printf "%b%s%b\n> " "${BLUE}description [${GREEN}" "$default_desc" "${BLUE}]${RESET}"
    129   read -r repo_desc
    130   repo_desc=${repo_desc:-$default_desc}
    131 
    132   printf "%b%s%b\n> " "${BLUE}owner [${GREEN}" "$default_owner" "${BLUE}]${RESET}"
    133   read -r owner
    134   owner=${owner:-$default_owner}
    135 
    136   printf "%b%s%b\n> " \
    137     "${BLUE}clone url [${GREEN}" "$url_prefix/$repo_name.git" "${BLUE}]${RESET}"
    138   read -r clone_url
    139   clone_url=${clone_url:-$url_prefix/$repo_name}.git
    140 
    141   # start creating repo
    142   git init --bare "$repo_path"
    143 
    144   echo "writing gitout metadata..."
    145   printf "%s\n" "$repo_desc" > "$repo_path/description"
    146   printf "%s\n" "$owner" > "$repo_path/owner"
    147   printf "%s\n" "$clone_url" > "$repo_path/url"
    148 
    149   echo "setting visibility..."
    150   [ "$exported" = "1" ] && : >> "$repo_path/git-daemon-export-ok"
    151   [ "$hidden" = "1" ] && : >> "$repo_path/gitout-no-index"
    152 
    153   echo "installing gitout post-receive hook..."
    154   ln -sf "$GRM_POSTRECV_HOOK" "$repo_path/hooks/post-receive"
    155   mkdir -p "$repo_path/hooks/post-receive.d"
    156   for hook in "$(ls "$GRM_POSTRECV_HOOKS_DIR")"; do
    157     ln -sf "$GRM_POSTRECV_HOOKS_DIR/$hook" "$repo_path/hooks/post-receive.d/$hook"
    158   done
    159 
    160   echo "done!"
    161 }
    162 
    163 grm_remove() {
    164   [ $# -gt 0 ] || { echo "no repo name given, exiting..."; exit 1; }
    165 
    166   for repo in "$@"
    167   do
    168     printf "remove %s? [y/N] " "$repo"
    169     read -r resp
    170     if echo "$resp" | grep -iq "^y$"; then
    171       rm -rf "${repos_root:?}/${repo:?}.git" || continue;
    172       rm -rf "${web_root:?}/${repo:?}" || continue;
    173     fi
    174   done
    175   # only rebuild index if gitout exists
    176   command -v gitout_index -m "${ME_URL}" >/dev/null && rebuild_index &
    177   wait
    178 }
    179 
    180 grm_list() {
    181   case "$1" in
    182     public)
    183       find "${repos_root}/." ! -name . -prune        \
    184         -type d -name "*.git"                        \
    185         -exec test -e "{}/git-daemon-export-ok" \;   \
    186         -exec test ! -e "{}/gitout-no-index" \;      \
    187         -exec basename {} '.git' \; | sort -f ;;
    188     private)
    189       find "${repos_root}/." ! -name . -prune        \
    190         -type d -name "*.git"                        \
    191         -exec test ! -e "{}/git-daemon-export-ok" \; \
    192         -exec basename {} '.git' \; | sort -f ;;
    193     hidden|unlisted)
    194       find "${repos_root}/." ! -name . -prune        \
    195         -type d -name "*.git"                        \
    196         -exec test -e "{}/git-daemon-export-ok" \;   \
    197         -exec test -e "{}/gitout-no-index" \;        \
    198         -exec basename {} '.git' \; | sort -f ;;
    199     *)
    200       find "${repos_root}/." ! -name . -prune \
    201         -type d -name "*.git"                 \
    202         -exec basename {} '.git' \; | sort -f ;;
    203   esac
    204 }
    205 
    206 grm_recompile() {
    207   for repo_name in "$@"
    208   do
    209     recompile_repo "$repo_name" &
    210   done
    211   rebuild_index &
    212   wait
    213   echo "recompilation done!"
    214 }
    215 
    216 grm_recompileall() {
    217   grm_list \
    218     | sed -e 's/"/"\\""/g' -e 's/.*/"&"/' \
    219     | xargs "$0" rc
    220 }
    221 
    222 grm_info() {
    223   [ -z "$1" ] && { echo "no repo name given, exiting..."; exit 1; }
    224 
    225   repo_name=$1
    226   repo_dir="${repos_root}/${repo_name}.git"
    227 
    228   [ -d "$repo_dir" ] || { echo "can't find repo named $repo_name"; exit 1; }
    229   echo "name: $repo_name"
    230   printf "visibility: "
    231 
    232   if [ -e "${repo_dir}/git-daemon-export-ok" ]; then
    233     if [ -e "${repo_dir}/gitout-no-index" ]; then
    234       printf "%b\n" "${YELLOW}unlisted${RESET}"
    235     else
    236       printf "%b\n" "${GREEN}public${RESET}"
    237     fi
    238   else
    239     printf "%b\n" "${RED}private${RESET}"
    240   fi
    241 
    242   [ -f "${repo_dir}/description" ] && \
    243     echo "description: $(cat "${repo_dir}/description")"
    244 
    245   [ -f "${repo_dir}/owner" ] && \
    246     echo "owner: $(cat "${repo_dir}/owner")"
    247 
    248   [ -f "${repo_dir}/url" ] && \
    249     echo "url: $(cat "${repo_dir}/url")"
    250 }
    251 
    252 show_help() {
    253   cat << EOF
    254 usage: $prog_name <command> [<args>]
    255 
    256 Git repo manager, manage git repositories on self-hosted git servers.
    257 
    258 If you have created a 'git' user for managing git repositories, this
    259 script should be run as:
    260     $ doas -u git -- $prog_name <command> [<args>]
    261 or
    262     $ sudo -u git -- $prog_name <command> [<args>]
    263 
    264 commands:
    265     new                  create a new repo
    266     info repo_name       display metadata of the repo
    267     ls                   list all repos
    268     ls public            list public repos
    269     ls private           list private repos
    270     ls unlisted          list unlisted (hidden) repos
    271     rm repo1 [repo2..]   remove repos
    272     rc                   recompile gitout index
    273     rc repo1 [repo2..]   recompile gitout pages for repos,
    274                          and recompile index
    275     rca                  recompile all public repos
    276     help                 show help
    277 EOF
    278 }
    279 
    280 # parse subcommands
    281 case "$1" in
    282   new) cmd=new;;
    283   ls|list) cmd=list;;
    284   rm|remove) cmd=remove;;
    285   rc|recompile) cmd=recompile;;
    286   rca|recompileall) cmd=recompileall;;
    287   info) cmd=info;;
    288   *) { show_help; exit; };;
    289 esac
    290 
    291 shift
    292 grm_"$cmd" "$@"