1 #@ Include file for the make-release.sh generic release builder.
2 #@ It also needs three hooks: update_stable_hook() and update_release_hook(),
3 #@ which need to "git add" what they have modified, and test_release_hook(),
4 #@ (non-"grappa") called with the release tag name as an argument after the
5 #@ release commit: if it returns a non-0 status the release process is aborted.
6 #@ The "grappa" mode needs a current_version() hook, which has to set $VERSION
7 #@ to the current program version, expected as MAJOR.MINOR.UPDATE[-whatever]
26 : ${roff:=s-roff} # optional (command(1) tested)
33 : ${PROGRAM:?"Need \$PROGRAM"}
34 : ${UPROGRAM:?"Need \$UPROGRAM"}
35 # For announcement only.
36 : ${MANUAL:?"May need \$MANUAL for announcement references"}
38 # When we upload balls only.
39 : ${UPLOAD:?"Need \$UPLOAD URL for scp(1)"}
41 # For announcement mail only.
43 : ${ACCOUNT:?"May need mailx(1) -A \$ACCOUNT"}
44 : ${MAILTO:?"May need \$MAILTO for announcement"}
45 : ${MAILBCC:?"May need \$MAILBCC for announcement"}
49 ORIG_LC_ALL=${LC_ALL} LC_ALL=C
52 DATE_MAN=`${date} -u +'%B %d, %Y'`
53 DATE_ISO=`${date} -u +%Y-%m-%d`
57 [ ${#} -gt 0 ] && printf '%s ' "${@}"
69 headref="`${git} rev-parse --verify HEAD`"
71 for i in `${git} rev-parse --branches=stable master^{commit} \
73 if [ ${headref} = ${i} ]; then
78 if [ -z "${brref}" ]; then
79 echo >&2 'Not on the [master] or a [stable/*] branch'
80 [ -z "${grappa}" ] && exit 1
81 if yesno 'Are you sure you want grappa from '${headref}'?'; then :; else
82 echo >&2 'Bailing out'
86 if [ "`${git} status --porcelain --ignored |
87 ${awk} 'BEGIN{no=0}{++no}END{print no}'`" -ne 0 ]; then
88 echo >&2 'Directory not clean, see git status --ignored'
91 #brname="`git branch | sed -e '/^* /b X' -e d -e :X -e 's/^* //'`"
92 brname=`${git} symbolic-ref --short HEAD`
96 vmaj=`{ echo ${VERSION}; } | ${sed} -e 's/^\([^.]\{1,\}\).*/\1/'`
97 vmin=`{ echo ${VERSION}; } |
98 ${sed} -e 's/^[^.]\{1,\}\.\([^.]\{1,\}\).*/\1/'`
99 [ ${vmin} = ${VERSION} ] && VERSION=${VERSION}.0 vmin=0
100 vupd=`{ echo ${VERSION}; } |
101 ${sed} -e 's/^[^.]\{1,\}\.[^.]\{1,\}\.\([^.-]\{1,\}\).*/\1/'`
102 [ ${vupd} = ${VERSION} ] && VERSION=${VERSION}.0 vupd=0
105 if yesno 'Is '${PROGRAM}' <v'${REL}'> correct?'; then :; else
106 echo >&2 'Bailing out'
112 stblbrname=stable/v${vmaj}.${vmin} need_stblbrname=
113 brref=`${git} rev-parse --verify ${stblbrname} 2>/dev/null`
114 if [ -z "${brref}" ]; then
115 if yesno 'Create new branch '"${stblbrname}"' after release tag'; then
118 elif [ ${brref} != ${headref} ] || [ ${brname} != ${stblbrname} ]; then
119 echo >&2 "For ${REL} we should be on ${stblbrname}, not ${brname}"
120 echo >&2 'Bailing out'
124 relbrname=release/v${VERSION}
125 brref=`${git} rev-parse --verify ${relbrname} 2>/dev/null`
126 if [ -z "${brref}" ]; then :; else
127 echo >&2 "The ${relbrname} already exists"
128 echo >&2 'Bailing out'
136 if yesno 'Shall '${PROGRAM}' v'${REL}' have a symbolic name?'; then
137 printf ' ..and it shall be known as: '
139 if yesno 'Is '"${RELSYM}"' correct?'; then :; else
140 echo >&2 'Bailing out'
143 stblmsg="Bump ${UPROGRAM} v${REL} (\"${RELSYM}\"), ${DATE_ISO}"
144 relmsg="Bump ${UPROGRAM} v${REL}.ar (\"${RELSYM}\"), ${DATE_ISO}"
145 RELSYM=" (\"${RELSYM}\")"
147 stblmsg="Bump ${UPROGRAM} v${REL}, ${DATE_ISO}"
148 relmsg="Bump ${UPROGRAM} v${REL}.ar, ${DATE_ISO}"
152 update_stable_branch() {
153 LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${stblmsg}"
154 LC_ALL=${ORIG_LC_ALL} ${git} tag -s -f -m "${stblmsg}" v${REL}
156 if [ -n "${need_stblbrname}" ]; then
157 ${git} checkout -b ${stblbrname}
159 # Normally done in post-commit hook, but not once initially created
160 if yesno 'Shall i update stable/latest "symlink"?'; then
161 ${git} update-ref refs/heads/stable/latest ${stblbrname}
163 if yesno 'Shall i update stable/stable "symlink"?'; then
164 ${git} update-ref refs/heads/stable/stable ${stblbrname}
168 create_release_branch() {
169 if yesno 'Create release/ branch?'; then
170 ${git} checkout -b ${relbrname}
172 echo 'Updating files: calling update_release_hook'
175 LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${relmsg}"
176 LC_ALL=${ORIG_LC_ALL} ${git} tag -s -f -m "${relmsg}" v${REL}.ar
178 if yesno 'Shall i update release/latest "symlink"?'; then
179 ${git} update-ref refs/heads/release/latest ${relbrname}
181 if yesno 'Shall i update release/stable "symlink"?'; then
182 ${git} update-ref refs/heads/release/stable ${relbrname}
185 relbrname=${stblbrname}
189 check_timeline_branch() {
190 if [ ${relbrname} != ${stblbrname} ] &&
191 `${git} rev-parse --verify timeline^{commit} >/dev/null 2>&1` &&
192 yesno 'Shall i update [timeline]?'; then
193 ${git} checkout timeline
195 ${git} archive --format=tar "v${REL}.ar" | ${tar} -x -f -
197 LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${relmsg}"
202 [ ${relbrname} != ${stblbrname} ] && ${git} checkout ${stblbrname}
203 ${git} log --no-walk --decorate --oneline --branches --remotes
204 yesno 'Push git(1) repo?' && ${git} push
208 if [ ${relbrname} != ${stblbrname} ] && yesno 'Create tarballs?'; then
213 # Repack with standard tar(1) to avoid new-style headers
214 ${git} archive --format=tar --prefix="${PROGRAM}-${REL}/" v${REL}.ar |
215 ( cd "${TMPDIR}" && ${tar} -x -f - )
218 # And use a portable format by default; ustar from 1988 is ok for us,
219 # but pax/posix from 2001 is even more forgiving and future aware
221 ${tar} --format=pax --version >/dev/null 2>&1 && fmt=--format=pax
222 ${tar} -c ${fmt} -f "${PROGRAM}-${REL}.tar" "${PROGRAM}-${REL}"
223 < "${PROGRAM}-${REL}.tar" ${xz} -e -C sha256 > "${PROGRAM}-${REL}.tar.xz"
224 < "${PROGRAM}-${REL}.tar" ${gzip} -9 > "${PROGRAM}-${REL}.tar.gz"
225 ${rm} "${PROGRAM}-${REL}.tar"
227 printf '' > "${PROGRAM}-${REL}.cksum"
228 ${openssl} sha1 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
229 ${openssl} sha256 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
230 ${openssl} sha512 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
231 ${openssl} sha1 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
232 ${openssl} sha256 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
233 ${openssl} sha512 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
235 echo >> "${PROGRAM}-${REL}.cksum"
236 ${gpg} --detach-sign --armor "${PROGRAM}-${REL}.tar.xz"
237 ${cat} "${PROGRAM}-${REL}.tar.xz.asc" >> "${PROGRAM}-${REL}.cksum"
238 ${gpg} --detach-sign --armor "${PROGRAM}-${REL}.tar.gz"
239 ${cat} "${PROGRAM}-${REL}.tar.gz.asc" >> "${PROGRAM}-${REL}.cksum"
241 [ -f "${PROGRAM}".cat1 ] &&
242 < "${PROGRAM}".cat1 ${xz} -e -C sha256 > "${PROGRAM}-${REL}.cat1.xz"
243 [ -f "${PROGRAM}".xcat1 ] &&
244 < "${PROGRAM}".xcat1 ${xz} -e -C sha256 > "${PROGRAM}-${REL}.xcat1.xz"
251 announcement_prepare() {
253 if yesno 'Prepare announcement?'; then :; else
258 if `${git} cat-file -e ${relbrname}:NEWS 2>/dev/null`; then
259 ${git} show ${relbrname}:NEWS > "${TMPDIR}/.${PROGRAM}-${REL}.news"
261 printf '' > "${TMPDIR}/.${PROGRAM}-${REL}.news"
264 { echo "${relmsg}"; echo; } > "${TMPDIR}/${PROGRAM}-${REL}.txt"
265 if [ -f .git/make-release.txt ]; then
267 if [ -n "${bigballs}" ] && [ -f "${TMPDIR}/${PROGRAM}-${REL}.cksum" ]
269 cks=`< "${TMPDIR}/${PROGRAM}-${REL}.cksum" \
270 ${sed} -e 's/ //' -e '/^$/,$d'`
271 < "${TMPDIR}/${PROGRAM}-${REL}.cksum" ${sed} '1,/^$/d' \
272 > "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
273 < .git/make-release.txt ${awk} \
274 -v INS="${cks}" -v SIGS="${TMPDIR}/.${PROGRAM}-${REL}.sigs" \
275 -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
276 /-----CHECKSUMS-----/{
279 for(i = 1; i <= atop; ++i){
280 match(a[i], /(\(.+\))/)
281 tfn = substr(a[i], RSTART + 1, RLENGTH - 2)
282 tpre = substr(a[i], 1, RSTART - 1)
283 tsuf = substr(a[i], RSTART + RLENGTH + 1)
284 if(fn == "" || fn != tfn)
285 printf "%s:\n", (fn = tfn)
286 printf " %6s %s\n", tpre, tsuf
290 /-----SIGNATURES-----/{
291 while((getline sl < SIGS) > 0)
296 while((getline sl < NEWS) > 0)
301 ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
302 ${rm} -f "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
304 < .git/make-release.txt ${awk} \
305 -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
307 while((getline sl < NEWS) > 0)
312 ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
314 elif [ -f "${TMPDIR}/.${PROGRAM}-${REL}.news" ]; then
315 ${cat} "${TMPDIR}/.${PROGRAM}-${REL}.news" >> \
316 "${TMPDIR}/${PROGRAM}-${REL}.txt"
319 ${rm} -f "${TMPDIR}/.${PROGRAM}-${REL}.news"
321 LC_ALL=${ORIG_LC_ALL} ${EDITOR} "${TMPDIR}/${PROGRAM}-${REL}.txt"
323 # HTML convert ready for S-Web42
325 < "${TMPDIR}/${PROGRAM}-${REL}.txt" ${awk} -v manual="${MANUAL}" '
328 print "<?begin?><?mode icewatsm?><pre>"
340 while(match(s, /(\\?https?\??:\/\/[^ ]*)/)){
341 pre = substr(s, 1, RSTART - 1)
342 mat = substr(s, RSTART, RLENGTH)
343 s = substr(s, RSTART + RLENGTH)
344 if("\\" == substr(mat, 1, 1))
348 if(match(mat, /^https\?/))
349 mat = "https" substr(xt = mat, RSTART + 6)
350 if(match(mat, /sdaoden\.eu/))
351 mat = "<?lref" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
353 mat = "<?href" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
362 /^[ ]*s-.*-mode[ ]*$/{
365 /^(NOTES|ChangeLog)/{
371 /^(Appendix|git\(1\) shortlog)/{
387 # Create S-Web42 local references for the possible anchors:
388 # *XY*# / $XY# / -XY# / `XY${APO}# / `~XY${APO}# / "XY"#
389 # (where the mdocmx(7) anchor follows the number sign).
390 # Ideally the anchors have been automatically expanded by
391 # make-news-anchors.sh before.
393 /(^|\(|[ ]+)("[^"]+"|\*[^\*]+\*|`[^'${APO}']+'${APO}'|[-~][-#\/:_.0-9a-zA-Z]+|\$[_0-9a-zA-Z]+)#[0-9]+/))
395 pre = (RSTART > 1) ? substr(s, 1, RSTART - 1) : ""
396 mat = substr(s, RSTART, RLENGTH)
397 s = substr(s, RSTART + RLENGTH)
399 # Unfortunately groups are not supported
400 if(match(mat, /^(\(|[ ]+)/) != 0 && RLENGTH > 0){
401 pre = pre substr(mat, 1, RLENGTH)
402 mat = substr(mat, RSTART + RLENGTH)
405 match(mat, /#[0-9]+/)
406 targ = substr(mat, RSTART + 1, RLENGTH)
407 mat = substr(mat, 1, RSTART - 1)
408 res = res pre "<?lreft " manual "#" targ "<>" mat "?>"
416 print "</pre><?end?>"
418 ' > "${TMPDIR}/.${PROGRAM}-ann.html"
422 if [ -n "${bigballs}" ] && yesno 'Upload archives'; then :; else
428 echo "-put ${PROGRAM}-${REL}.tar.xz"
429 echo "-rm ${PROGRAM}-latest.tar.xz"
430 echo "-ln -s ${PROGRAM}-${REL}.tar.xz ${PROGRAM}-latest.tar.xz"
432 echo "-put ${PROGRAM}-${REL}.tar.xz.asc"
433 echo "-rm ${PROGRAM}-latest.tar.xz.asc"
434 echo "-ln -s ${PROGRAM}-${REL}.tar.xz.asc ${PROGRAM}-latest.tar.xz.asc"
436 echo "-put ${PROGRAM}-${REL}.tar.gz"
437 echo "-rm ${PROGRAM}-latest.tar.gz"
438 echo "-ln -s ${PROGRAM}-${REL}.tar.gz ${PROGRAM}-latest.tar.gz"
440 echo "-put ${PROGRAM}-${REL}.tar.gz.asc"
441 echo "-rm ${PROGRAM}-latest.tar.gz.asc"
442 echo "-ln -s ${PROGRAM}-${REL}.tar.gz.asc ${PROGRAM}-latest.tar.gz.asc"
444 if [ -n "${anntxt}" ]; then
445 echo "-put ${PROGRAM}-${REL}.txt"
446 echo "-rm ${PROGRAM}-latest.txt"
447 echo "-ln -s ${PROGRAM}-${REL}.txt ${PROGRAM}-latest.txt"
450 echo "-chmod 0644 ${PROGRAM}-${REL}.*"
452 ${sftp} -b - ${UPLOAD}
455 announcement_send() {
456 if [ -n "${anntxt}" ] && yesno 'Send announcement mail?'; then
457 LC_ALL=${ORIG_LC_ALL} ${MAILX} -A ${ACCOUNT} \
458 -s "[ANN]ounce of ${UPROGRAM} v${REL}${RELSYM}" \
459 -q "${TMPDIR}/${PROGRAM}-${REL}.txt" \
460 -b ${MAILBCC} ${MAILTO}
464 create_grappa_env() {
465 echo 'Updating files: calling update_release_hook'
467 echo 'E allora io quasi quasi prendo il treno'
471 if [ ${#} -ne 0 ]; then
472 if [ ${#} != 2 ] || [ "${1}" != grappa ] || [ -z "${2}" ]; then
473 echo >&2 'You have a hell of a lot to learn about Rock'"'"'n Roll'
480 echo 'Preparing a release on commit '"${headref}"
481 if [ -z "${grappa}" ]; then
482 printf ' The HEAD is %s\nName of release tag: ' "${brname}"
489 echo 'Grappa to be brought from '"${brname}"' to '"${grappa}"
491 printf 'Program version is %s, packager release addition shall be: ' \
494 VERSION="${VERSION}-${REL}"
498 if ${git} rev-parse --verify ${grappa} >/dev/null 2>/dev/null; then :; else
501 ${git} checkout ${i} ${grappa}
503 ${git} archive --format=tar ${headref} | ${tar} -x -f -
507 echo 'Updating files: calling update_stable_hook'
510 if [ -z "${grappa}" ]; then
512 create_release_branch
513 test_release_hook v${REL}.ar || exit 1
514 check_timeline_branch
525 # Finally remove the temporary instances than ran this
526 ${rm} -f .git/make-release.*