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