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:
| M | README.md | | | 18 | +++++++++++++----- |
| M | git-publish | | | 83 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
| A | post-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"