diff options
Diffstat (limited to 'git-snapsign')
-rwxr-xr-x | git-snapsign | 210 |
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 |