#!/bin/sh
set -eu
MSGS=''
add_msg() {
MSGS="$MSGS $1"
}
MSG_USAGE="$(cat <<-'EOF'
Usage: git permalink [-phV] FILE [LINENO]
EOF
)"
add_msg USAGE
MSG_HELP="$(cat <<-'EOF'
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.
EOF
)"
add_msg HELP
MSG_MISSING_FILE="$(cat <<-'EOF'
Missing FILE argument.
EOF
)"
add_msg MISSING_FILE
MSG_UNSUPPORTED_ORIGIN="$(cat <<-'EOF'
Unsupported origin: %s.
Add a template override to use git-permalink (see
"man git-permalink" for instructions).
EOF
)"
add_msg UNSUPPORTED_ORIGIN
MSG_OPEN="$(cat <<-'EOF'
Opening %s
EOF
)"
add_msg OPEN
#
# End translatable strings
#
dump_translatable_strings() {
for msg in $MSGS; do
eval "echo \"\$MSG_$msg\"" > src/locale/"$msg".en.txt
done
cat <<-'EOF'
#!/bin/sh
# shellcheck disable=2034
set -eu
EOF
for msg in $MSGS; do
# shellcheck disable=2016
printf "MSG_%s=\"\$(cat '@LOCALEDIR@/@LANG@/LC_MESSAGES/@NAME@/%s.@LANG@.txt')\"\n" \
"$msg" "$msg"
done
}
if [ -n "${GIT_PERMALINK_DUMP_TRANSLATABLE_STRINGS:-}" ]; then
dump_translatable_strings
exit
fi
if [ -r '@LIBEXECDIR@/@NAME@/load-messages.sh' ]; then
# shellcheck disable=1091
. '@LIBEXECDIR@/@NAME@/load-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://euandreh.xyz/%s.git/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