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:
| M | Makefile | | | 19 | ++++++++++++------- |
| A | git-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