aboutsummaryrefslogtreecommitdiffstats
path: root/git-snapsign
diff options
context:
space:
mode:
Diffstat (limited to 'git-snapsign')
-rwxr-xr-xgit-snapsign210
1 files changed, 210 insertions, 0 deletions
diff --git a/git-snapsign b/git-snapsign
new file mode 100755
index 0000000..c5e37d4
--- /dev/null
+++ b/git-snapsign
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Jesus E.
+#
+# 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 <https://www.gnu.org/licenses/>.
+#
+VERSION='1.0.0'
+
+HELP_MESSAGE="\
+usage: $(basename "$0") [--dry-run] [--force] [-s <key-id>] [-F <fmt>] [-p <pfx>] -t <tag>
+
+ Create a detached signature for an archive of <tag> and add it to the tag's
+ notes in the refs/notes/signatures/<fmt> namespace.
+
+ This is useful for cgit's snapshot support.
+
+ -d, --dry-run Don't actually add any signature refs
+ -f, --force Overwrite any existing signature
+ -F, --format <fmt> Archive format to use; either \"tar.gz\", \"tar.lz\", \"tar.xz\",
+ \"tgz\", \"tar\" or \"zip\". For default \"tar.lz\".
+ -p, --prefix <pfx> Snapsnot prefix to use instead of the repository basename
+ -P, --push Upload signature to remote git
+ -t, --tag <tag> Git tag name
+ -s, --signature <key-id> Create the signature using <key-id> instead of the default
+ -v, --version Show version of $(basename "$0")
+ -h, --help This message
+
+Examples:
+ git-snapsign -t 1.0.0
+ git-snapsign --format tar.gz -t 1.0.0
+"
+
+#-------------
+# variables
+#-------------
+
+# Require Git repository
+eval "$(
+ echo "$OPTIONS_SPEC" \
+ | git rev-parse ||
+ echo exit $?
+)"
+
+gpg="$(git config gpg.program)"
+toplevel="$(git rev-parse --show-toplevel)"
+
+dryrun="n"
+force="n"
+format="tar.lz"
+keyid="$(git config user.signingkey)"
+prefix="$(basename "${toplevel%.git}")"
+
+_cgit_snappfx="$(git config --local cgit.snapshot-prefix)"
+_repo_snappfx="$(git config --local repo.snapshot-prefix)"
+
+if [ -n "${_cgit_snappfx}" ]; then
+ prefix="${_cgit_snappfx})"
+elif [ -n "${_repo_snappfx}" ]; then
+ prefix="${_repo_snappfx})"
+fi
+
+ref="$(git symbolic-ref HEAD 2> /dev/null | sed -e 's/refs\/heads\///')"
+if [[ -n $ref ]]; then
+ gtbranch=$ref
+else
+ gtbranch=$ref
+fi
+
+check_format() {
+ if [ "${format}" != "tar.gz" ] \
+ && [ "${format}" != "tar.lz" ] \
+ && [ "${format}" != "tar.xz" ] \
+ && [ "${format}" != "tgz" ] \
+ && [ "${format}" != "tar" ] \
+ && [ "${format}" != "zip" ];
+ then
+ echo -e "fatal: format not supported by git: ${format}"
+ exit 1
+ fi
+}
+
+#---------
+# core
+#---------
+if [ -z "${1}" ]; then
+ echo "$HELP_MESSAGE"
+fi
+
+for param in "$@"; do
+ shift
+ case "$param" in
+ "--dry-run") set -- "$@" "-d" ;;
+ "--force") set -- "$@" "-f" ;;
+ "--format") set -- "$@" "-F" ;;
+ "--prefix") set -- "$@" "-p" ;;
+ "--push") set -- "$@" "-P" ;;
+ "--signature") set -- "$@" "-s" ;;
+ "--tag") set -- "$@" "-t" ;;
+ "--version") set -- "$@" "-v" ;;
+ "--help") set -- "$@" "-h" ;;
+ *) set -- "$@" "$param" ;;
+ esac
+done
+
+while getopts ":dfPhvF:s:p:t:" opt; do
+ case $opt in
+ d)
+ dryrun=y
+ ;;
+ f)
+ force=y
+ ;;
+ F)
+ format=$OPTARG
+ check_format "$@"
+ ;;
+ p)
+ prefix="${OPTARG}"
+ ;;
+ P)
+ git push origin "${gtbranch}" refs/notes/*
+ ;;
+ s)
+ keyid="$OPTARG"
+ ;;
+ t)
+ if ! git rev-parse --verify "${OPTARG}" >/dev/null 2>&1; then
+ echo -e "fatal: failed to verify tag: ${OPTARG}"
+ exit 1
+ fi
+ tag="${OPTARG}"
+ ;;
+ v)
+ echo -e "$VERSION"
+ exit 0
+ ;;
+ h)
+ echo -e "$HELP_MESSAGE"
+ exit 0
+ ;;
+ \?)
+ echo "Invalid option -$OPTARG" >&2
+ exit 1
+ ;;
+ esac
+done
+
+tmpdir="$(mktemp -dp"${TMPDIR:-/tmp}")"
+trap 'rm -rf "${tmpdir}"' EXIT HUP INT QUIT TERM
+
+if [[ -n "${tag}" ]]; then
+ archive="${tmpdir}/${prefix}-${tag#v}.${format}"
+
+ if [ "$format" == "tar.lz" ]; then
+ git archive --format=tar --prefix "${prefix}-${tag#v}/" \
+ "${tag}" | lzip -c > "${archive}"
+ elif [ "$format" == "tar.xz" ]; then
+ git archive --format=tar --prefix "${prefix}-${tag#v}/" \
+ "${tag}" | xz -c > "${archive}"
+ else
+ git archive --format "${format}" --prefix "${prefix}-${tag#v}/" \
+ --output "${archive}" "${tag}"
+ fi
+
+ if ! "${gpg:-gpg}" --output "${archive}.asc" --armor \
+ --sign-with "${keyid}" --detach-sign <"${archive}"
+ then
+ echo -e "fatal: failed to sign archive"
+ exit 1
+ fi
+
+ if [ "${dryrun}" == "y" ]; then
+ sig_hash="$(git hash-object --stdin <"${archive}.asc")"
+ echo -e "dry-run: add signature (${sig_hash}) note for tag ${tag}"
+ else
+ sig_hash="$(git hash-object -w --stdin <"${archive}.asc")"
+ fi
+
+ if [ "${force}" == "y" ]; then
+ git notes --ref="refs/notes/signatures/${format}" \
+ add --force -C "${sig_hash}" "${tag}"
+ _interger=$?
+ if [[ "$_interger" -eq 0 ]]; then
+ echo -e "Forcing add signature (${sig_hash}) note for tag ${tag}"
+ else
+ exit 1
+ fi
+ else
+ git notes --ref="refs/notes/signatures/${format}" \
+ add -C "${sig_hash}" "${tag}"
+ _interger=$?
+ if [[ "$_interger" -eq 0 ]]; then
+ echo -e "Add signature (${sig_hash}) note for tag ${tag}"
+ else
+ echo -e "Signature already exists or invalid tag"
+ exit 1
+ fi
+ fi
+fi