#!/usr/bin/env bash # git-shell-commands(5) subcommand: interactive repo manager. # Run: ssh -t git@git.kumardamani.net manage # Also symlinked as no-interactive-login, so a bare interactive ssh # (ssh -t git@git.kumardamani.net) lands here directly. cmds=/srv/git/git-shell-commands valid_name() { case "$1" in ""|*[!a-zA-Z0-9._-]*|*..*) return 1 ;; *) return 0 ;; esac } list_repos() { printf '%-24s %-8s %s\n' REPO STATE DESCRIPTION for repo in /srv/git/*.git; do [ -d "$repo" ] || continue name="${repo##*/}" name="${name%.git}" if [ -f "$repo/git-daemon-export-ok" ]; then state=public else state=private fi desc="$(cat "$repo/description" 2>/dev/null)" case "$desc" in Unnamed*) desc= ;; esac printf '%-24s %-8s %s\n' "$name" "$state" "$desc" done } ask_name() { printf 'repo name: ' read -r name if ! valid_name "$name"; then echo "invalid name '$name' (allowed: a-z 0-9 . _ -)" >&2 return 1 fi } while true; do echo echo "== git repo manager ==" echo " l) list repos" echo " c) create repo" echo " p) publish repo" echo " h) hide repo" echo " d) set description" echo " x) delete repo" echo " q) quit" printf '> ' read -r choice || break case "$choice" in l) list_repos ;; c) "$cmds/create" ;; # create prompts for name + settings itself p) ask_name && "$cmds/publish" "$name" ;; h) ask_name && "$cmds/hide" "$name" ;; d) ask_name && { printf 'description: ' read -r text "$cmds/desc" "$name" "$text" } ;; x) ask_name && [ -d "/srv/git/$name.git" ] && { printf 'type the repo name again to confirm DELETE: ' read -r confirm if [ "$confirm" = "$name" ]; then rm -rf "/srv/git/$name.git" echo "deleted '$name'" else echo "aborted" fi } ;; q|quit|exit) break ;; *) echo "unknown choice '$choice'" ;; esac done