git-repo

Tools for sharing git bare repositories
git clone git://git.meso-star.fr/git-repo.git
Log | Files | Refs | README | LICENSE

commit 4a9c7ead24aa6412882698ef1e39e88abe420aa4
parent 2d19ae8f3dae8353b18b15badaa24e86b2bf9bcb
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Sun, 25 May 2025 22:00:55 +0200

Add a post-receive hook to the publicly exposed repo

It updates the repository's HTML pages and the HTML index listing public
repositories. Check that no other post-receive hook has already been
defined.

Note that from now on, all error messages are printed on the standard
error. Some were printed on standard output.

Diffstat:
MREADME.md | 18+++++++++++++-----
Mgit-publish | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Apost-receive.in | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 162 insertions(+), 31 deletions(-)

diff --git a/README.md b/README.md @@ -1,22 +1,30 @@ -# git repo +# git repository tools Setting up a git bare [dumb] repository with the possibility of shared write access given to a group. +Help in making public a git bare repsitory. ## Requirements - git - POSIX shell +- [stagit](https://codemadness.org/git/stagit/log.html) - [mandoc](https://mandoc.bsd.lv) ## Installation make install -## License +## Licenses Copyright (C) 2024, 2025 |Méso|Star> (contact@meso-star.com) -It is free software released under the GPL v3+ license: GNU GPL version -3 or later. You are welcome to redistribute them under certain -conditions; refer to the COPYING file for details. +This program is free software released under the GPL v3+ license: GNU +GPL version 3 or later. You are welcome to redistribute them under +certain conditions; refer to the COPYING file for details. + +### post-receive-hook.in + +Copyright (c) 2015-2024 Hiltjo Posthuma <hiltjo@codemadness.org> + +MIT/X Consortium License diff --git a/git-publish b/git-publish @@ -22,9 +22,15 @@ set -e ######################################################################## die() { + rm -rf "${tmpdir}" # cleanup temporary files exit "${1:-1}" # return status code (default is 1) } +# Configure signal processing +trap 'die $?' EXIT + +tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/git_publis_XXXXXX")" + synopsis() { >&2 printf \ @@ -37,44 +43,47 @@ check_resources() # path if [ ! -e "$1"/favicon.png ] \ || [ ! -e "$1"/logo.png ] \ || [ ! -e "$1"/style.css ]; then - printf '%s: resources are missing\n' "$1" + >&2 printf '%s: resources are missing\n' "$1" return 1 fi } -check_repo() # path +check_directory() # path { - cd "$1" - - if ! is_bare_repo="$(git rev-parse --is-bare-repository 2> /dev/null)" \ - || [ "${is_bare_repo}" = "false" ]; then - printf '%s: not a git bare repository\n' "$1" + if [ -z "$1" ] || ! cd "$1" 2> /dev/null; then + >&2 printf '%s: not a directory\n' "$1" return 1 fi cd "${OLDPWD}" } -check_directory() # path +# Inputs: +# - repo: git bare repository +check_repo() { - if [ -z "$1" ] || ! cd "$1" 2> /dev/null; then - printf '%s: not a directory\n' "$1" + cd "${repo}" + + if ! is_bare_repo="$(git rev-parse --is-bare-repository 2> /dev/null)" \ + || [ "${is_bare_repo}" = "false" ]; then + >&2 printf 'not a git bare repository\n' return 1 fi cd "${OLDPWD}" } -publish() # git bare repo +# Inputs: +# - base_url: base URL under which the git HTML repository is exposed +# - dir_git: directory where to publish the git repository +# - dir_www: directory where to publish the git repository's HTML pages +# - repo: git bare repository +publish_repo() { - repo="$1" - - check_repo "${repo}" repo_name=$(basename "${repo}" ".git") # Publish the git repository, i.e. create a symbolic link to it in the # publicly exposed directory - mkdir -p "${dir_git}" repo_git="${dir_git}/${repo_name}.git" ln -sf "${repo}" "${repo_git}" @@ -92,6 +101,29 @@ publish() # git bare repo cd "${OLDPWD}" } +# Inputs: +# - base_url: base URL under which the git HTML repository is exposed +# - dir_git: directory where to publish the git repository +# - dir_www: directory where to publish the git repository's HTML pages +# - repo: git bare repository +setup_post_receive_hook() +{ + sed -e "s#@DIR_GIT@#${dir_git}#g" \ + -e "s#@DIR_WWW@#${dir_www}#g" \ + -e "s#@BASE_URL@#${base_url}#g" \ + post-receive.in > "${tmpdir}/post-receive" + + if [ -e "${repo}/hooks/post-receive" ] \ + && ! diff "${repo}/hooks/post-receive" \ + "${tmpdir}/post-receive" > /dev/null; then + >&2 printf 'post-receive hook already exist\n' + return 1; + fi + + cp "${tmpdir}/post-receive" "${repo}/hooks/post-receive" + chmod 755 "${repo}/hooks/post-receive" +} + ######################################################################## # The script ######################################################################## @@ -106,16 +138,15 @@ while getopts ":g:u:w:" opt; do u) base_url="${OPTARG}" ;; g) dir_git="${OPTARG}" ;; # git directory w) dir_www="${OPTARG}" ;; # WWW directory - *) synopsis; die ;; + *) synopsis; exit 1 ;; esac done - # Check mandatory options -[ -n "${base_url}" ] || { printf 'Base url is missing\n'; die; } -[ -n "${dir_git}" ] || { printf 'git directory is missing\n'; die; } -[ -n "${dir_www}" ] || { printf 'WWW directory is missing\n'; die; } -[ "${OPTIND}" -lt $# ] || { synopsis; die; } +[ "${OPTIND}" -le $# ] || { synopsis; exit 1; } +[ -n "${base_url}" ] || { >&2 printf 'Base url is missing\n'; exit 1; } +[ -n "${dir_git}" ] || { >&2 printf 'git directory is missing\n'; exit 1; } +[ -n "${dir_www}" ] || { >&2 printf 'WWW directory is missing\n'; exit 1; } check_directory "${dir_git}" check_directory "${dir_www}" @@ -124,13 +155,13 @@ check_resources "${dir_www}" # Skip parsed arguments shift $((OPTIND - 1)) -printf '%s\n' "$@" | while read -r repository; do - printf '%s: ' "${repository}" - publish "${repository}" +printf '%s\n' "$@" | while read -r repo; do + printf '%s: ' "${repo}" + check_repo + publish_repo + setup_post_receive_hook printf 'done\n' done # [Re]generate index of publicly exposed repositories stagit-index "${dir_git}/"*/ > "${dir_www}/index.html" - -die 0 diff --git a/post-receive.in b/post-receive.in @@ -0,0 +1,92 @@ +#!/bin/sh + +# Copyright (c) 2015-2024 Hiltjo Posthuma <hiltjo@codemadness.org> +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +# generic git post-receive hook. +# change the config options below and call this script in your post-receive +# hook or symlink it. +# +# usage: $0 [name] +# +# if name is not set the basename of the current directory is used, +# this is the directory of the repo when called from the post-receive script. + +export LC_CTYPE="en_US.UTF-8" + +name="$1" +if test "${name}" = ""; then + name=$(basename "$(pwd)") +fi + +# config +# paths must be absolute. +reposdir="@DIR_GIT@" +dir="${reposdir}/${name}" +htmldir="@DIR_WWW@" +stagitdir="/" +destdir="${htmldir}${stagitdir}" +cachefile=".cache" +# /config + +if ! test -d "${dir}"; then + echo "${dir} does not exist" >&2 + exit 1 +fi +cd "${dir}" || exit 1 + +# detect git push -f +force=0 +while read -r old new ref; do + test "${old}" = "0000000000000000000000000000000000000000" && continue + test "${new}" = "0000000000000000000000000000000000000000" && continue + + hasrevs=$(git rev-list "${old}" "^${new}" | sed 1q) + if test -n "${hasrevs}"; then + force=1 + break + fi +done + +# strip .git suffix. +r=$(basename "${name}") +d=$(basename "${name}" ".git") +printf "[%s] stagit HTML pages... " "${d}" + +mkdir -p "${destdir}/${d}" +cd "${destdir}/${d}" || exit 1 + +# remove commits and ${cachefile} on git push -f, this recreated later on. +if test "${force}" = "1"; then + rm -f "${cachefile}" + rm -rf "commit" +fi + +# make index. +stagit-index "${reposdir}/"*/ > "${destdir}/index.html" + +# make pages. +stagit -c "${cachefile}" -u "@BASE_URL@/$d/" "${reposdir}/${r}" + +ln -sf log.html index.html +ln -sf ../style.css style.css +ln -sf ../logo.png logo.png + +echo "done"