update_git_source_package: use 12 char long hash for bump commits
[maintainer-tools.git] / update_git_source_package.sh
1 #!/usr/bin/env bash
2 # update_git_source_package.sh: (c) 2023 Jo-Philipp Wich <jo@mein.io>
3 # Licensed under the terms of the Apache License, Version 2.0
4
5 MAKEFILE=$1
6 COMMIT=${2:-HEAD}
7 TOPDIR=$3
8
9 [ -n "$MAKEFILE" ] || {
10 cat <<-EOT
11 Usage: $0 <package name or makefile path> [revision] [topdir]
12
13 Update an OpenWrt package Makefile with PKG_SOURCE_PROTO:=git to
14 the given upstream revision (or 'HEAD' if omitted).
15
16 The script either accepts a package name, like "netifd" or
17 an absolute or relative path to a Makefile, e.g.
18 "./package/utils/ucode/Makefile".
19
20 If the revision argument is ommitted, the package is updated
21 to the current HEAD of the remote Git repository.
22
23 By default, this script tries to infer the buildroot directory
24 from the package Makefile path but it may be overridden by
25 passing it as 3rd argument. This is useful in situation where
26 the Makefile to update does not reside within an OpenWrt buildroot.
27
28 On success, the package Makefile is automatically modified and
29 the resulting changes are committed in the currently checked
30 buildroot branch using a standard commit message format.
31 EOT
32
33 exit 1
34 }
35
36 MAKE=$(which gmake) || MAKE=$(which make)
37 FIND=$(which gfind) || FIND=$(which find)
38
39 [ -x "$MAKE" ] || {
40 echo "Unable to locate `make` executable" >&2
41 exit 1
42 }
43
44 [ -x "$FIND" ] || {
45 echo "Unable to locate `find` executable" >&2
46 exit 1
47 }
48
49 [ -e "$MAKEFILE" ] || {
50 MAKEFILE=$("$FIND" "${TOPDIR:-.}/package/" -type f -path "*/$MAKEFILE/Makefile" | head -n1)
51 }
52
53 [ -f "$MAKEFILE" ] || {
54 echo "Usage: $0 <path/to/Makefile> [target commit] [path/to/buildroot/topdir]"
55 exit 1
56 }
57
58 grep -sq BuildPackage "$MAKEFILE" || {
59 echo "The file '$MAKEFILE' does not appear to be an OpenWrt package Makefile." >&2
60 exit 1
61 }
62
63 [ -n "$TOPDIR" ] || {
64 TOPDIR=$(cd "$(dirname "${MAKEFILE%/*}")"; pwd)
65
66 while [ "$TOPDIR" != "/" ]; do
67 TOPDIR=$(dirname "$TOPDIR")
68 [ -f "$TOPDIR/rules.mk" ] && break
69 done
70
71 [ -f "$TOPDIR/rules.mk" ] || {
72 echo "Unable to determine buildroot directory." >&2
73 exit 1
74 }
75 }
76
77 export TOPDIR
78
79 eval $(
80 "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" \
81 var.PKG_NAME \
82 var.PKG_RELEASE \
83 var.PKG_SOURCE_PROTO \
84 var.PKG_SOURCE_URL \
85 var.PKG_SOURCE_DATE \
86 var.PKG_SOURCE_VERSION \
87 var.PKG_MIRROR_HASH
88 )
89
90 case "$PKG_SOURCE_PROTO:$PKG_SOURCE_URL" in
91 git:http://*|git:https://*|git:git://*|git:file:*)
92 :
93 ;;
94 *)
95 echo "Unsupported combination of source protocol ('$PKG_SOURCE_PROTO') and url ('$PKG_SOURCE_URL')." >&2
96 exit 1
97 ;;
98 esac
99
100 TEMP_GIT_DIR=
101
102 for signal in INT TERM EXIT; do
103 trap '
104 [ -d "$TEMP_GIT_DIR" ] && rm -rf "$TEMP_GIT_DIR";
105 git -C "$(dirname "$MAKEFILE")" checkout --quiet "$(basename "$MAKEFILE")"
106 ' $signal
107 done
108
109 TEMP_GIT_DIR=$(mktemp -d) || {
110 echo "Unable to create temporary Git directory." >&2
111 exit 1
112 }
113
114 git clone --bare "$PKG_SOURCE_URL" "$TEMP_GIT_DIR" || {
115 echo "Unable to clone Git repository '$PKG_SOURCE_URL'." >&2
116 exit 1
117 }
118
119 GIT_LOG="$(git -C "$TEMP_GIT_DIR" log \
120 --reverse --no-merges \
121 --abbrev=12 \
122 --format="%h %s" \
123 "$PKG_SOURCE_VERSION..$COMMIT" \
124 )" || {
125 echo "Unable to determine changes from commit '$PKG_SOURCE_VERSION' to '$COMMIT'." >&2
126 exit 1
127 }
128
129 GIT_DATE_COMMIT=$(git -C "$TEMP_GIT_DIR" log \
130 -1 --format='%cd %H' \
131 --date='format:%Y-%m-%d' \
132 "$COMMIT" \
133 ) || {
134 echo "Unable to determine target commit ID and date." >&2
135 exit 1
136 }
137
138 sed -i -r \
139 -e "/PKG_SOURCE_VERSION/s#\<$PKG_SOURCE_VERSION\>#${GIT_DATE_COMMIT#* }#" \
140 -e "/PKG_SOURCE_DATE/s#\<$PKG_SOURCE_DATE\>#${GIT_DATE_COMMIT% *}#" \
141 "$MAKEFILE"
142
143 if [ -n "$PKG_RELEASE" ] && [ "$PKG_RELEASE" != "1" ]; then
144 sed -i -r \
145 -e "/PKG_RELEASE/s#\<$PKG_RELEASE\>#1#" \
146 "$MAKEFILE"
147 fi
148
149 eval $(
150 "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" \
151 var.PKG_SOURCE
152 )
153
154 "$MAKE" -C "$(dirname "$MAKEFILE")" download || {
155 echo "Unable to download and pack updated Git sources." >&2
156 exit 1
157 }
158
159 DL_HASH=$(sha256sum "$TOPDIR/dl/$PKG_SOURCE") || {
160 echo "Unable to determine archive checksum." >&2
161 exit 1
162 }
163
164 sed -i -r \
165 -e "/PKG_MIRROR_HASH/s#\<$PKG_MIRROR_HASH\>#${DL_HASH%% *}#" \
166 "$MAKEFILE"
167
168 git -C "$(dirname "$MAKEFILE")" commit \
169 --signoff --no-edit \
170 --message "$PKG_NAME: update to Git $COMMIT (${GIT_DATE_COMMIT% *})" \
171 --message "$GIT_LOG" \
172 "$(basename "$MAKEFILE")"
173
174 "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" check || {
175 echo "WARNING: Package check failed for updated Makefile!"
176 exit 1
177 }