git-repo

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

commit 2d19ae8f3dae8353b18b15badaa24e86b2bf9bcb
parent e8b15c5359ce7e0295badde85902c7d5db866945
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Sat, 24 May 2025 22:55:53 +0200

Add the git-publish command

It helps make git repositories public by exposing them through a public
directory (e.g. served by git-daemon) and generating HTML pages of their
commits, refs, license and README.

Published repositories still don't have a post-receive hook that updates
HTML pages after a commit. In addition, the git-publish man page is also
missing.

Diffstat:
MMakefile | 19++++++++++++-------
Agit-publish | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 148 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile @@ -18,23 +18,28 @@ # Default install directories PREFIX = /usr/local -MANPREFIX = ${PREFIX}/share/man +BINPREFIX = $(PREFIX)/bin +MANPREFIX = $(PREFIX)/share/man # Nothing to do default: install: - mkdir -p $(DESTDIR)$(PREFIX)/bin - cp -f git-repo $(DESTDIR)$(PREFIX)/bin - chmod 755 $(DESTDIR)$(PREFIX)/bin/git-repo - mkdir -p $(DESTDIR)$(MANPREFIX)/man1 - cp -f git-repo.1 $(DESTDIR)$(MANPREFIX)/man1 - chmod 644 $(DESTDIR)$(MANPREFIX)/man1/git-repo.1 + install() { mode="$$1"; prefix="$$2"; shift 2; \ + mkdir -p "$${prefix}"; \ + cp "$$@" "$${prefix}"; \ + chmod "$${mode}" "$$@"; \ + }; \ + install 755 "$(DESTDIR)$(BINPREFIX)" git-publish; \ + install 755 "$(DESTDIR)$(BINPREFIX)" git-repo; \ + install 644 "$(DESTDIR)$(MANPREFIX)/man1" git-repo.1 uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/git-publish rm -f $(DESTDIR)$(PREFIX)/bin/git-repo rm -f $(DESTDIR)$(MANPREFIX)/man1/git-repo.1 lint: + shellcheck -o all git-publish shellcheck -o all git-repo mandoc -Wbase -Tlint git-repo.1 diff --git a/git-publish b/git-publish @@ -0,0 +1,136 @@ +#!/bin/sh + +# Copyright (C) 2024, 2025 |Méso|Star> (contact@meso-star.com) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -e + +######################################################################## +# Helper functions +######################################################################## +die() +{ + exit "${1:-1}" # return status code (default is 1) +} + +synopsis() +{ + >&2 printf \ +'usage: %s [-u base_url] [-g dir_git] [-w dir_www] repository ...\n' \ + "${0##*/}" +} + +check_resources() # path +{ + if [ ! -e "$1"/favicon.png ] \ + || [ ! -e "$1"/logo.png ] \ + || [ ! -e "$1"/style.css ]; then + printf '%s: resources are missing\n' "$1" + return 1 + fi +} + +check_repo() # 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" + return 1 + fi + + cd "${OLDPWD}" +} + +check_directory() # path +{ + if [ -z "$1" ] || ! cd "$1" 2> /dev/null; then + printf '%s: not a directory\n' "$1" + return 1 + fi + + cd "${OLDPWD}" +} + +publish() # git bare 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}" + + # Create directory publicly served by the WWW daemon + repo_www="${dir_www}/${repo_name}" + mkdir -p "${repo_www}" + + # Generate HTML pages for the repository to be published + cd "${repo_www}" + stagit -c .cache -u "${base_url}/${repo_name}/" "${repo_git}" + ln -sf ./log.html ./index.html + ln -sf "${dir_www}"/style.css ./style.css + ln -sf "${dir_www}"/logo.png ./logo.png + ln -sf "${dir_www}"/favicon.png ./favicon.png + cd "${OLDPWD}" +} + +######################################################################## +# The script +######################################################################## +base_url="${GIT_PUBLISH_BASE_URL:-}" +dir_git="${GIT_PUBLISH_DIR_GIT:-/srv/git}" +dir_www="${GIT_PUBLISH_DIR_WWW:-/srv/www}" + +# Parse input arguments +OPTIND=1 +while getopts ":g:u:w:" opt; do + case "${opt}" in + u) base_url="${OPTARG}" ;; + g) dir_git="${OPTARG}" ;; # git directory + w) dir_www="${OPTARG}" ;; # WWW directory + *) synopsis; die ;; + 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; } + +check_directory "${dir_git}" +check_directory "${dir_www}" +check_resources "${dir_www}" + +# Skip parsed arguments +shift $((OPTIND - 1)) + +printf '%s\n' "$@" | while read -r repository; do + printf '%s: ' "${repository}" + publish "${repository}" + printf 'done\n' +done + +# [Re]generate index of publicly exposed repositories +stagit-index "${dir_git}/"*/ > "${dir_www}/index.html" + +die 0