add a script for bumping packages using Git repository sources
authorJo-Philipp Wich <jo@mein.io>
Fri, 10 Nov 2023 11:07:40 +0000 (12:07 +0100)
committerJo-Philipp Wich <jo@mein.io>
Fri, 10 Nov 2023 11:07:40 +0000 (12:07 +0100)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
update_git_source_package.sh [new file with mode: 0755]

diff --git a/update_git_source_package.sh b/update_git_source_package.sh
new file mode 100755 (executable)
index 0000000..a2f57f1
--- /dev/null
@@ -0,0 +1,176 @@
+#!/usr/bin/env bash
+# update_git_source_package.sh: (c) 2023 Jo-Philipp Wich <jo@mein.io>
+# Licensed under the terms of the Apache License, Version 2.0
+
+MAKEFILE=$1
+COMMIT=${2:-HEAD}
+TOPDIR=$3
+
+[ -n "$MAKEFILE" ] || {
+       cat <<-EOT
+       Usage: $0 <package name or makefile path> [revision] [topdir]
+
+       Update an OpenWrt package Makefile with PKG_SOURCE_PROTO:=git to
+       the given upstream revision (or 'HEAD' if omitted).
+
+       The script either accepts a package name, like "netifd" or
+       an absolute or relative path to a Makefile, e.g.
+       "./package/utils/ucode/Makefile".
+
+       If the revision argument is ommitted, the package is updated
+       to the current HEAD of the remote Git repository.
+
+       By default, this script tries to infer the buildroot directory
+       from the package Makefile path but it may be overridden by
+       passing it as 3rd argument. This is useful in situation where
+       the Makefile to update does not reside within an OpenWrt buildroot.
+
+       On success, the package Makefile is automatically modified and
+       the resulting changes are committed in the currently checked
+       buildroot branch using a standard commit message format.
+       EOT
+
+       exit 1
+}
+
+MAKE=$(which gmake) || MAKE=$(which make)
+FIND=$(which gfind) || FIND=$(which find)
+
+[ -x "$MAKE" ] || {
+       echo "Unable to locate `make` executable" >&2
+       exit 1
+}
+
+[ -x "$FIND" ] || {
+       echo "Unable to locate `find` executable" >&2
+       exit 1
+}
+
+[ -e "$MAKEFILE" ] || {
+       MAKEFILE=$("$FIND" "${TOPDIR:-.}/package/" -type f -path "*/$MAKEFILE/Makefile" | head -n1)
+}
+
+[ -f "$MAKEFILE" ] || {
+       echo "Usage: $0 <path/to/Makefile> [target commit] [path/to/buildroot/topdir]"
+       exit 1
+}
+
+grep -sq BuildPackage "$MAKEFILE" || {
+       echo "The file '$MAKEFILE' does not appear to be an OpenWrt package Makefile." >&2
+       exit 1
+}
+
+[ -n "$TOPDIR" ] || {
+       TOPDIR=$(cd "$(dirname "${MAKEFILE%/*}")"; pwd)
+
+       while [ "$TOPDIR" != "/" ]; do
+               TOPDIR=$(dirname "$TOPDIR")
+               [ -f "$TOPDIR/rules.mk" ] && break
+       done
+
+       [ -f "$TOPDIR/rules.mk" ] || {
+               echo "Unable to determine buildroot directory." >&2
+               exit 1
+       }
+}
+
+export TOPDIR
+
+eval $(
+       "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" \
+               var.PKG_NAME \
+               var.PKG_RELEASE \
+               var.PKG_SOURCE_PROTO \
+               var.PKG_SOURCE_URL \
+               var.PKG_SOURCE_DATE \
+               var.PKG_SOURCE_VERSION \
+               var.PKG_MIRROR_HASH
+)
+
+case "$PKG_SOURCE_PROTO:$PKG_SOURCE_URL" in
+       git:http://*|git:https://*|git:git://*|git:file:*)
+               :
+       ;;
+       *)
+               echo "Unsupported combination of source protocol ('$PKG_SOURCE_PROTO') and url ('$PKG_SOURCE_URL')." >&2
+               exit 1
+       ;;
+esac
+
+TEMP_GIT_DIR=
+
+for signal in INT TERM EXIT; do
+       trap '
+               [ -d "$TEMP_GIT_DIR" ] && rm -rf "$TEMP_GIT_DIR";
+               git -C "$(dirname "$MAKEFILE")" checkout --quiet "$(basename "$MAKEFILE")"
+       ' $signal
+done
+
+TEMP_GIT_DIR=$(mktemp -d) || {
+       echo "Unable to create temporary Git directory." >&2
+       exit 1
+}
+
+git clone --bare "$PKG_SOURCE_URL" "$TEMP_GIT_DIR" || {
+       echo "Unable to clone Git repository '$PKG_SOURCE_URL'." >&2
+       exit 1
+}
+
+GIT_LOG="$(git -C "$TEMP_GIT_DIR" log \
+       --reverse --no-merges \
+       --format="%h %s" \
+       "$PKG_SOURCE_VERSION..$COMMIT" \
+)" || {
+       echo "Unable to determine changes from commit '$PKG_SOURCE_VERSION' to '$COMMIT'." >&2
+       exit 1
+}
+
+GIT_DATE_COMMIT=$(git -C "$TEMP_GIT_DIR" log \
+       -1 --format='%cd %H' \
+       --date='format:%Y-%m-%d' \
+       "$COMMIT" \
+) || {
+       echo "Unable to determine target commit ID and date." >&2
+       exit 1
+}
+
+sed -i -r \
+       -e "/PKG_SOURCE_VERSION/s#\<$PKG_SOURCE_VERSION\>#${GIT_DATE_COMMIT#* }#" \
+       -e "/PKG_SOURCE_DATE/s#\<$PKG_SOURCE_DATE\>#${GIT_DATE_COMMIT% *}#" \
+       "$MAKEFILE"
+
+if [ -n "$PKG_RELEASE" ] && [ "$PKG_RELEASE" != "1" ]; then
+       sed -i -r \
+               -e "/PKG_RELEASE/s#\<$PKG_RELEASE\>#1#" \
+               "$MAKEFILE"
+fi
+
+eval $(
+       "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" \
+               var.PKG_SOURCE
+)
+
+"$MAKE" -C "$(dirname "$MAKEFILE")" download || {
+       echo "Unable to download and pack updated Git sources." >&2
+       exit 1
+}
+
+DL_HASH=$(sha256sum "$TOPDIR/dl/$PKG_SOURCE") || {
+       echo "Unable to determine archive checksum." >&2
+       exit 1
+}
+
+sed -i -r \
+       -e "/PKG_MIRROR_HASH/s#\<$PKG_MIRROR_HASH\>#${DL_HASH%% *}#" \
+       "$MAKEFILE"
+
+git -C "$(dirname "$MAKEFILE")" commit \
+       --signoff --no-edit \
+       --message "$PKG_NAME: update to Git $COMMIT (${GIT_DATE_COMMIT% *})" \
+       --message "$GIT_LOG" \
+       "$(basename "$MAKEFILE")"
+
+"$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" check || {
+       echo "WARNING: Package check failed for updated Makefile!"
+       exit 1
+}