gitpages

A collection of scripts to securely webhost and publish git repositories.
git clone https://scm.kuandu.systems/git-raw/gitpages.git
Log | Files | Refs | README | LICENSE

commit 052d646b8b11edaf112b209a0978e748a097ba8a
parent aa8c525fe42d7e243bdf56be8e819d5e678b3800
Author: Fred Großkopf <fred@kuandu.systems>
Date:   Fri,  1 May 2026 23:04:40 +0200

Adds gitpages-init-repos.sh

Diffstat:
Agitpages-init-repos.sh | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest-gitpages-init-repos.sh | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 232 insertions(+), 0 deletions(-)

diff --git a/gitpages-init-repos.sh b/gitpages-init-repos.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +set -eu + +log() { printf 'info: %s\n' "$1"; } +warn() { printf 'warning: %s\n' "$1" >&2; } +error() { + printf 'error: %s\n' "$1" >&2 + exit 1 +} + +# Global temp directory (set once in main) +WORKDIR="" + +cleanup() { [ -n "${WORKDIR-}" ] && rm -rf "$WORKDIR"; } +trap cleanup EXIT INT TERM + +ask() { + prompt="$1" + current="${2:-}" + + # Only show prompt if stdin is a terminal + if [ -t 0 ]; then + if [ -n "$current" ]; then + printf '%s [%s]: ' "$prompt" "$current" >&2 + else + printf '%s: ' "$prompt" >&2 + fi + fi + + read -r answer + case "$answer" in + "") printf '%s\n' "$current" ;; + *) printf '%s\n' "$answer" ;; + esac +} + +update_post_receive_hook() { + repo_dir="$1" + + + # Install hook into repo + hook_dir="$repo_dir/hooks" + hook_file="$hook_dir/post-receive" + + mkdir -p "$hook_dir" + cp "$POST_RECEIVE" "$hook_file" + chmod 755 "$hook_file" + log "Installed post-receive hook in $repo_dir" +} + +process_repo() { + repo="$1" + repo_name=$(basename "$repo" .git) + + desc_file="$repo/description" + owner_file="$repo/owner" + url_file="$repo/url" + + # Read current values + current_desc="" + [ -f "$desc_file" ] && current_desc="$(cat "$desc_file")" + + current_owner="" + [ -f "$owner_file" ] && current_owner="$(cat "$owner_file")" + + current_url="" + [ -f "$url_file" ] && current_url="$(cat "$url_file")" + + # Show repo boundary + printf '## Repository: %s ##\n' "$repo_name" + + # Ask for description + ask_desc="$WORKDIR/ask_desc" + ask "Description" "$current_desc" > "$ask_desc" + new_desc="$(cat "$ask_desc")" + if [ -n "$new_desc" ]; then + printf '%s\n' "$new_desc" > "$desc_file" + fi + + # Ask for owner + ask_owner="$WORKDIR/ask_owner" + ask "Owner/Contact" "$current_owner" > "$ask_owner" + new_owner="$(cat "$ask_owner")" + if [ -n "$new_owner" ]; then + printf '%s\n' "$new_owner" > "$owner_file" + fi + + # Ask for URL + ask_url="$WORKDIR/ask_url" + ask "URL" "$current_url" > "$ask_url" + new_url="$(cat "$ask_url")" + if [ -n "$new_url" ]; then + printf '%s\n' "$new_url" > "$url_file" + fi + + update_post_receive_hook "$repo" +} + +main() { + # Decide source directory + if [ $# -eq 1 ]; then + GIT_SRC="$1" + else + CONFIG="/etc/gitpages.conf" + [ -r "$CONFIG" ] || error "Config file $CONFIG not read. Please create it or run as ./gitpages-init-repos.sh /path/to/repos" + GIT_SRC=$(awk -F '=' ' + $1 ~ /^[[:space:]]*GIT_SRC[[:space:]]*$/ { + gsub(/^[[:space:]]+/, "", $2) + gsub(/[[:space:]]+$/, "", $2) + print $2 + exit + } + ' "$CONFIG") + [ -n "$GIT_SRC" ] || error "GIT_SRC not set in $CONFIG" + fi + + [ -d "$GIT_SRC" ] || error "Directory '$GIT_SRC' not found" + + # Create one working temp dir, removed by trap + WORKDIR="$(mktemp -d -t gitpages_ask.XXXXXX)" || + error "mktemp failed" + + # Find script directory and locate post‑receive + script_dir=$(cd "$(dirname "$0")" && pwd -P) + POST_RECEIVE="$script_dir/post-receive.hook" + [ -f "$POST_RECEIVE" ] || error "post-receive helper not found in $script_dir" + + # Gather repos into "$@" + set -- $(find "$GIT_SRC" -maxdepth 1 -name '*.git' -type d) + + # Process each repo + for repo in "$@"; do + if [ -d "$repo" ]; then + process_repo "$repo" + fi + done + + log "Initialization complete for all repos in $GIT_SRC" +} + +main "$@" diff --git a/test-gitpages-init-repos.sh b/test-gitpages-init-repos.sh @@ -0,0 +1,90 @@ +#!/bin/sh + +set -eu + +WORKDIR="" +TARGET="" + +log() { printf 'test: %s\n' "$1"; } +die() { printf 'test: error: %s\n' "$1" >&2; exit 1; } + +setup_dirs() { + WORKDIR="$(mktemp -d -t gitpages_test.XXXXXX)" || + die "mktemp failed" + + TARGET="$WORKDIR/repos" + mkdir "$TARGET" + + # Quiet git default‑branch hint + GIT_CONFIG_NOSYSTEM=1 \ + git config --global init.defaultBranch main + + log "created test workspace in $WORKDIR" +} + +setup_repos() { + git init --bare "$TARGET/foo.git" + git init --bare "$TARGET/bar.git" + log "created foo.git and bar.git" +} + +run_gitpages_init() { + log "running gitpages-init-repos.sh" + + # Feed 3 lines per repo: desc, owner, url + ( + printf '%s\n' "Description for foo" + printf '%s\n' "user@foo.org" + printf '%s\n' "https://foo.example.com" + + printf '%s\n' "Description for bar" + printf '%s\n' "user@bar.org" + printf '%s\n' "https://bar.example.com" + ) | ./gitpages-init-repos.sh "$TARGET" +} + +inspect_repos() { + log "contents of repos:" + for repo in "$TARGET"/*.git; do + if [ -d "$repo" ]; then + repo_name=$(basename "$repo" .git) + printf '\n== %s ==\n' "$repo_name" + + if [ -f "$repo/description" ]; then + printf 'desc:\n'; cat "$repo/description" + else + printf 'desc: (MISSING!)\n' + fi + + if [ -f "$repo/owner" ]; then + printf '\nowner:\n'; cat "$repo/owner" + else + printf 'owner: (MISSING!)\n' + fi + + if [ -f "$repo/url" ]; then + printf '\nurl:\n'; cat "$repo/url" + else + printf 'url: (MISSING!)\n' + fi + + hook="$repo/hooks/post-receive" + if [ -f "$hook" ]; then + printf '\npost-receive (head 10):\n'; head -10 "$hook" + else + printf 'post-receive hook: (MISSING!)\n' + fi + fi + done +} + +main() { + setup_dirs + setup_repos + run_gitpages_init + inspect_repos + + log "test complete" +} + +main