#!/bin/sh set -eu # # Translatable strings # _G() { echo "$1" } MSG_USAGE="$(_G 'Usage: git permalink [-phV] FILE [LINENO]')" MSG_HELP="$(_G ' Options: -p only print the link, don'"'"'t try to open it -h, --help show this help message -V, --version print the version number See "man git-permalink" for more information. ')" MSG_MISSING_FILE="$(_G 'Missing FILE argument.')" MSG_UNSUPPORTED_ORIGIN="$(_G 'Unsupported origin: %s. Add an template override to use git-permalink (see "man git-permalink.1" for instructions).')" MSG_OPEN="$(_G 'Opening %s')" if [ -r '@LIBEXECDIR@/@NAME@/load-locale-messages.sh' ]; then . '@LIBEXECDIR@/@NAME@/load-locale-messages.sh' fi # # Documentation functions # usage() { printf '%s\n' "$MSG_USAGE" } help() { printf '\n%s\n' "$MSG_HELP" } version() { printf 'git-permalink-@VERSION@ @DATE@\n' } # # Core functions # normalize_origin() { if echo "$ORIGIN" | grep -q '^git@'; then NAME="$(echo "$ORIGIN" | cut -d: -f2 | cut -d/ -f1)" URL="$(echo "$ORIGIN" | cut -d@ -f2 | cut -d: -f1)" ORIGIN="https://$URL/$NAME/$REPOSITORY" fi } lineno_with_l() { if echo "$MYLINENO" | grep -q -- -; then P1="$(echo "$MYLINENO" | cut -d- -f1)" P2="$(echo "$MYLINENO" | cut -d- -f2)" printf '#L%s-L%s' "$P1" "$P2" elif [ -n "$MYLINENO" ]; then printf '#L%s' "${MYLINENO}" else printf '' fi } euandreh() { printf 'https://git.euandreh.xyz/%s/tree/%s?id=%s%s\n' \ "$REPOSITORY" "$FILE" "$COMMIT" "${MYLINENO:+#n$MYLINENO}" } sourcehut() { printf '%s/tree/%s/item/%s%s\n' \ "$ORIGIN" "$COMMIT" "$FILE" "${MYLINENO:+#L$MYLINENO}" } kernel() { printf '%s/tree/%s?id=%s%s\n' \ "$ORIGIN" "$FILE" "$COMMIT" "${MYLINENO:+#n$MYLINENO}" } savannah() { ORIGIN="$(echo "$ORIGIN" | sed 's|gnu.org/git|gnu.org/cgit|')" printf '%s/tree/%s?id=%s%s\n' \ "$ORIGIN" "$FILE" "$COMMIT" "${MYLINENO:+#n$MYLINENO}" } notabug() { normalize_origin printf '%s/src/%s/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "$(lineno_with_l)" } codeberg() { normalize_origin printf '%s/src/commit/%s/%s%s\n' \ "$ORIGIN" "$COMMIT" "$FILE" "$(lineno_with_l)" } bitbucket() { normalize_origin MYLINENO="${MYLINENO:+#lines-$(echo "$MYLINENO" | tr '-' ':')}" printf '%s/src/%s/%s%s\n' \ "$ORIGIN" "$COMMIT" "$FILE" "$MYLINENO" } pagure() { printf '%s/blob/%s/f/%s%s\n' \ "$ORIGIN" "$COMMIT" "$FILE" "${MYLINENO:+#_$MYLINENO}" } gitlab() { normalize_origin printf '%s/-/blob/%s/%s%s\n' \ "$ORIGIN" "$COMMIT" "$FILE" "${MYLINENO:+#L$MYLINENO}" } github() { normalize_origin printf '%s/blob/%s/%s%s\n' \ "$ORIGIN" "$COMMIT" "$FILE" "$(lineno_with_l)" } guess_permalink() { if [ -n "$OVERRIDE_CF" ]; then # shellcheck disable=2059 printf "$OVERRIDE_CF\n" "$COMMIT" "$FILE" elif [ -n "$OVERRIDE_FC" ]; then # shellcheck disable=2059 printf "$OVERRIDE_FC\n" "$FILE" "$COMMIT" else case "$ORIGIN" in *euandreh.xyz*) euandreh ;; *git.sr.ht*) sourcehut ;; *git.kernel.org*) kernel ;; *git.savannah.gnu.org*) savannah ;; *notabug.org*) notabug ;; *codeberg.org*) codeberg ;; *bitbucket.org*) bitbucket ;; *pagure.io*) pagure ;; *gitlab.com*) gitlab ;; *github.com*) github ;; *) # shellcheck disable=2059 printf "$MSG_UNSUPPORTED_ORIGIN\n" "$ORIGIN" >&2 exit 1 ;; esac fi } # # Main # for flag in "$@"; do case "$flag" in --) break ;; --help) usage help exit ;; --version) version exit ;; *) ;; esac done PRINTONLY=false while getopts 'phV' flag; do case "$flag" in p) PRINTONLY=true ;; h) usage help exit ;; V) version exit ;; *) usage >&2 exit 2 ;; esac done shift $((OPTIND - 1)) if [ -z "${1:-}" ]; then printf '%s\n\n' "$MSG_MISSING_FILE" >&2 usage >&2 exit 2 fi FILE="$1" MYLINENO="${2:-}" COMMIT="$(git rev-parse HEAD)" ORIGIN="$(git config remote.origin.url)" OVERRIDE_CF="$(git config git-permalink.template-commit-file ||:)" OVERRIDE_FC="$(git config git-permalink.template-file-commit ||:)" REPOSITORY="$(basename "$PWD")" LINK="$(guess_permalink)" if [ "$PRINTONLY" = true ]; then echo "$LINK" else # shellcheck disable=2059 printf "$MSG_OPEN\n" "$LINK" >&2 xdg-open "$LINK" fi