#!/bin/sh
#
# Copyright (c) 2026 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

#
# github-mirror [push-options]
#
#	Push changes to a github mirror of the local repository at the
#	working directory.
#
#	If the last push started less than 20sec ago, sleep the
#	remaining 20sec before starting afresh.
#
#	User must configure:
#
#	- a remote `github' with ssh URL
#
#	- a remote `github.draft' with ssh URL
#
#	- an ssh key pair `tnf-keys/github(.pub)' with push access to
#	  the `github' remote repository
#
#	- a _different_ ssh key pair `tnf-keys/github.draft(.pub)' with
#	  push access to the `github.draft' remote repository (note
#	  that github only allows each such ssh key to have access to
#	  only one repository at a time, so every repository must have
#	  its own key pair)
#
#	- a writable subdirectory `netbsd-sync/' of the .git directory
#
#	User must not run multiple github-mirror invocations on the
#	same repository in parallel.
#

set -Ceu

: "${GITHUB_SECONDS_PER_PUSH:=10}"

GIT_DIR=$(git rev-parse --git-dir)
cd -- "$GIT_DIR"

# Github currently recommends limiting to six pushes per repository per
# minute, so make sure to breathe for up to 20sec (two pushes -- maybe
# not treated as the same repository, but one might be a clone of the
# other and therefore counted as the same repository, so let's not risk
# it).
#
# https://web.archive.org/web/20260326150915/https://docs.github.com/en/repositories/creating-and-managing-repositories/repository-limits
#
# We use netbsd-sync/github.done as the reference time, or if it
# doesn't exist, netbsd-sync/github.start (e.g., maybe it was
# interrupted and the mv at the bottom never finished), or if that
# doesn't exist either, the current time just in case.
#
starttime=$(stat -f %m netbsd-sync/github.done 2>/dev/null ||
    stat -f %m netbsd-sync/github.start 2>/dev/null ||
    date +%s)
endtime=$(date +%s)
if [ $((endtime - starttime)) -le $((2*GITHUB_SECONDS_PER_PUSH)) ]; then
	${SLEEP:-sleep} \
	    $((2*GITHUB_SECONDS_PER_PUSH - (endtime - starttime) + 1))
fi

# Mark the time when we start.  Truncate the file if it already exists
# so we update the mtime, which we will use later.  (utimes(2) would
# work but it's not as conveniently accessible in the shell as
# truncating the file.)  Lock the file so we detect accidental
# concurrent syncs -- shouldn't happen, but let's avoid overloading
# things if it does.
#
exec 3>|netbsd-sync/github.start
flock --nonblock --exclusive 3 3>&3 || {
	printf >&2 'github-mirror: %s: concurrent sync, aborting\n' "$(pwd)"
	exit 1
}

GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh} -i tnf-keys/github" \
git push --force --prune --quiet "$@" github \
    'refs/heads/*:refs/heads/*' \
    'refs/tags/*:refs/tags/*' \
    # end of public refspecs

GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh} -i tnf-keys/github.draft" \
git push --force --prune --quiet "$@" github.draft \
    "$(git symbolic-ref HEAD):refs/heads/github-default-branch" \
    'refs/namespaces/draft/refs/heads/*:refs/heads/*' \
    # end of draft refspecs

# Record the starting time of the last completed sync.
#
mv -f netbsd-sync/github.start netbsd-sync/github.done
