diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 000000000..eec9b36dc --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,119 @@ +#!/bin/sh +# +# This hook checks that all local sources specified in the staged APKBUILDs +# are staged too or already committed and that checksums are correct. +# +set -eu + +# Maximal allowed size (in bytes) of a file. +FILE_SIZE_LIMIT=262144 # 256 kiB + + +if ! command -v sha512sum >/dev/null; then + # macOS / BSDs (?) don't have sha512sum, but shasum. + alias sha512sum='shasum -a 512' +fi + +error() { + printf '\033[0;31mpre-commit:\033[0m %s\n' "$1" >&2 # red +} + +# Prints paths of created or modified files being committed. +changed_files() { + git diff-index \ + --name-only \ + --cached \ + --diff-filter=ACMR HEAD \ + -- "$@" +} + +# Prints file names and checksums (in format :) of local +# sources specified in the APKBUILD ($1). +apkbuild_local_sources() { + apkbuild="$1" + + set +eu + . "$apkbuild" || { + error "$apkbuild is invalid" + return 1 + } + set -eu + + status=0 + : ${source:=""} + for src in $source; do + # Skip remote sources. + case "$src" in */*) continue;; esac + + echo "$sha512sums" | awk -v src="$src" ' + { if ($2 == src) { ok=1; print($2 ":" $1) } } + END { if (ok != 1) exit 1 }' || { + status=1 + error "${apkbuild%/*}: file \"$src\" is missing in \$sha512sums (hint: run pmbootstrap checksum)" + } + done + + return $status +} + +# check if given object is a symlink +is_symlink() { + test "$(git ls-files --stage "$1" | awk '{print $1}')" = "120000" +} + +# Checks that all local sources specified in the APKBUILD file ($1) are +# available in git tree and checksums are correct. +check_local_sources() { + local apkbuild="$1" + local startdir="${apkbuild%/*}" + local status=0 + local checksum_act checksum_exp content filename line sources + + sources=$(apkbuild_local_sources "$apkbuild") + for line in $sources; do + filename=${line%%:*} + checksum_exp=${line#*:} + + if ! git cat-file -e ":$startdir/$filename" 2>/dev/null; then + error "$startdir: missing file \"$filename\"" + status=1 + continue + fi + + if is_symlink ":$startdir/$filename"; then + continue + fi + + checksum_act=$(git show ":$startdir/$filename" | sha512sum) + if [ "$checksum_act" != "$checksum_exp -" ]; then + local cmd="pmbootstrap checksum $(basename "$startdir")" + error "$startdir: bad checksum for file \"$filename\" (hint: run $cmd)" + status=1 + fi + done + + return $status +} + +# Checks if the file ($1) being committed is not bigger than FILE_SIZE_LIMIT. +check_file_size() { + local path="$1" + local size + + size=$(git cat-file -s ":$path") + if [ $size -gt $FILE_SIZE_LIMIT ]; then + local size_kb=$(( size / 1024 )) + + error "file \"$path\" is quite big ($(( size / 1024 )) kiB), better put a remote url in source=" + return 1 + fi +} + + +for apkbuild in $(changed_files '**/APKBUILD'); do + check_local_sources "$apkbuild" +done + +for path in $(changed_files); do + check_file_size "$path" +done diff --git a/.githooks/prepare-commit-msg b/.githooks/prepare-commit-msg new file mode 100755 index 000000000..598464518 --- /dev/null +++ b/.githooks/prepare-commit-msg @@ -0,0 +1,49 @@ +#!/bin/sh +# +# This hook adds prefix "/: " to the commit message when +# committing changes of a single package. +# +MSG_FILE="$1" +SOURCE="$2" + +longest_common_prefix() { + awk -F/ ' + (NR == 1) { split($0, prefix); prefix_len = NF } + (NR > 1) { + for (i = 1; i <= prefix_len; i++) { + if (prefix[i] != $i) { + prefix_len = i - 1; break + } + } + } + (prefix_len == 0) { exit } + END { + res = prefix[1] + for (i = 2; i <= prefix_len; i++) { + res = res FS prefix[i] + } + print(res) + }' +} + +prepend_msg() { + local prefix="$1" + + printf '%s\n%s\n' "$prefix" "$(cat "$MSG_FILE")" > "$MSG_FILE" +} + + +# Do nothing if message has been given using -m, template, merge etc. +[ -z "$SOURCE" ] || exit 0 + +lcp=$(git diff-index --name-only --cached HEAD | longest_common_prefix) + +case "$lcp" in + device/*/*) prepend_msg "$(echo "$lcp" | cut -d/ -f3): ";; + # Multiple packages touched for same device category + # More logic could be added to detect if they all belong to same device + device/*) ;; + [^.]*/*) prepend_msg "$(echo "$lcp" | cut -d/ -f1-2): ";; +esac + +exit 0