1 #@ Include file for the make-release.sh generic release builder.
2 #@ It also needs two hooks: update_stable_hook(), update_release_hook(),
3 #@ which need to "git add" what they have modified.
4 #@ The "grappa" mode needs a current_version() hook, which has to set $VERSION
5 #@ to the current program version, expected as MAJOR.MINOR.UPDATE[-whatever]
7 : ${PROGRAM:?"Need \$PROGRAM"}
8 : ${UPROGRAM:?"Need \$UPROGRAM"}
9 # For announcement only.
10 : ${MANUAL:?"May need \$MANUAL for announcement references"}
12 # When we upload balls only.
13 : ${UPLOAD:?"Need \$UPLOAD URL for scp(1)"}
15 # For announcement mail only.
17 : ${ACCOUNT:?"May need mailx(1) -A \$ACCOUNT"}
18 : ${MAILTO:?"May need \$MAILTO for announcement"}
19 : ${MAILBCC:?"May need \$MAILBCC for announcement"}
38 : ${roff:=s-roff} # optional (command(1) tested)
45 ORIG_LC_ALL=${LC_ALL} LC_ALL=C
48 DATE_MAN=`${date} -u +'%B %d, %Y'`
49 DATE_ISO=`${date} -u +%Y-%m-%d`
53 [ ${#} -gt 0 ] && printf '%s ' "${@}"
65 headref="`${git} rev-parse --verify HEAD`"
67 for i in `${git} rev-parse --branches=stable master^{commit} \
69 if [ ${headref} = ${i} ]; then
74 if [ -z "${brref}" ]; then
75 echo >&2 'Not on the [master] or a [stable/*] branch'
76 [ -z "${grappa}" ] && exit 1
77 if yesno 'Are you sure you want grappa from '${headref}'?'; then :; else
78 echo >&2 'Bailing out'
82 if [ "`${git} status --porcelain --ignored |
83 ${awk} 'BEGIN{no=0}{++no}END{print no}'`" -ne 0 ]; then
84 echo >&2 'Directory not clean, see git status --ignored'
87 #brname="`git branch | sed -e '/^* /b X' -e d -e :X -e 's/^* //'`"
88 brname=`${git} symbolic-ref --short HEAD`
92 vmaj=`{ echo ${VERSION}; } | ${sed} -e 's/^\([^.]\{1,\}\).*/\1/'`
93 vmin=`{ echo ${VERSION}; } |
94 ${sed} -e 's/^[^.]\{1,\}\.\([^.]\{1,\}\).*/\1/'`
95 [ ${vmin} = ${VERSION} ] && VERSION=${VERSION}.0 vmin=0
96 vupd=`{ echo ${VERSION}; } |
97 ${sed} -e 's/^[^.]\{1,\}\.[^.]\{1,\}\.\([^.-]\{1,\}\).*/\1/'`
98 [ ${vupd} = ${VERSION} ] && VERSION=${VERSION}.0 vupd=0
101 if yesno 'Is '${PROGRAM}' <v'${REL}'> correct?'; then :; else
102 echo >&2 'Bailing out'
108 stblbrname=stable/v${vmaj}.${vmin} need_stblbrname=
109 brref=`${git} rev-parse --verify ${stblbrname} 2>/dev/null`
110 if [ -z "${brref}" ]; then
111 if yesno 'Create new branch '"${stblbrname}"' after release tag'; then
114 elif [ ${brref} != ${headref} ] || [ ${brname} != ${stblbrname} ]; then
115 echo >&2 "For ${REL} we should be on ${stblbrname}, not ${brname}"
116 echo >&2 'Bailing out'
120 relbrname=release/v${VERSION}
121 brref=`${git} rev-parse --verify ${relbrname} 2>/dev/null`
122 if [ -z "${brref}" ]; then :; else
123 echo >&2 "The ${relbrname} already exists"
124 echo >&2 'Bailing out'
132 if yesno 'Shall '${PROGRAM}' v'${REL}' have a symbolic name?'; then
133 printf ' ..and it shall be known as: '
135 if yesno 'Is '"${RELSYM}"' correct?'; then :; else
136 echo >&2 'Bailing out'
139 stblmsg="Bump ${UPROGRAM} v${REL} (\"${RELSYM}\"), ${DATE_ISO}"
140 relmsg="Bump ${UPROGRAM} v${REL}.ar (\"${RELSYM}\"), ${DATE_ISO}"
141 RELSYM=" (\"${RELSYM}\")"
143 stblmsg="Bump ${UPROGRAM} v${REL}, ${DATE_ISO}"
144 relmsg="Bump ${UPROGRAM} v${REL}.ar, ${DATE_ISO}"
148 update_stable_branch() {
149 LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${stblmsg}"
150 LC_ALL=${ORIG_LC_ALL} ${git} tag -s -f -m "${stblmsg}" v${REL}
152 if [ -n "${need_stblbrname}" ]; then
153 ${git} checkout -b ${stblbrname}
155 # Normally done in post-commit hook, but not once initially created
156 if yesno 'Shall i update stable/latest "symlink"?'; then
157 ${git} update-ref refs/heads/stable/latest ${stblbrname}
159 if yesno 'Shall i update stable/stable "symlink"?'; then
160 ${git} update-ref refs/heads/stable/stable ${stblbrname}
164 create_release_branch() {
165 if yesno 'Create release/ branch?'; then
166 ${git} checkout -b ${relbrname}
168 echo 'Updating files: calling update_release_hook'
171 LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${relmsg}"
172 LC_ALL=${ORIG_LC_ALL} ${git} tag -s -f -m "${relmsg}" v${REL}.ar
174 if yesno 'Shall i update release/latest "symlink"?'; then
175 ${git} update-ref refs/heads/release/latest ${relbrname}
177 if yesno 'Shall i update release/stable "symlink"?'; then
178 ${git} update-ref refs/heads/release/stable ${relbrname}
181 relbrname=${stblbrname}
185 check_timeline_branch() {
186 if [ ${relbrname} != ${stblbrname} ] &&
187 `${git} rev-parse --verify timeline^{commit} >/dev/null 2>&1` &&
188 yesno 'Shall i update [timeline]?'; then
189 ${git} checkout timeline
191 ${git} archive --format=tar "v${REL}.ar" | ${tar} -x -f -
193 LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${relmsg}"
198 [ ${relbrname} != ${stblbrname} ] && ${git} checkout ${stblbrname}
199 ${git} log --no-walk --decorate --oneline --branches --remotes
200 yesno 'Push git(1) repo?' && ${git} push
204 if [ ${relbrname} != ${stblbrname} ] && yesno 'Create tarballs?'; then
209 # Repack with standard tar(1) to avoid new-style headers
210 ${git} archive --format=tar --prefix="${PROGRAM}-${REL}/" v${REL}.ar |
211 ( cd "${TMPDIR}" && ${tar} -x -f - )
214 ${tar} -c -f "${PROGRAM}-${REL}.tar" "${PROGRAM}-${REL}"
215 < "${PROGRAM}-${REL}.tar" ${xz} -e -C sha256 > "${PROGRAM}-${REL}.tar.xz"
216 < "${PROGRAM}-${REL}.tar" ${gzip} -9 > "${PROGRAM}-${REL}.tar.gz"
217 ${rm} "${PROGRAM}-${REL}.tar"
219 printf '' > "${PROGRAM}-${REL}.cksum"
220 ${openssl} sha1 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
221 ${openssl} sha256 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
222 ${openssl} sha512 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
223 ${openssl} sha1 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
224 ${openssl} sha256 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
225 ${openssl} sha512 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
227 echo >> "${PROGRAM}-${REL}.cksum"
228 ${gpg} --detach-sign --armor "${PROGRAM}-${REL}.tar.xz"
229 ${cat} "${PROGRAM}-${REL}.tar.xz.asc" >> "${PROGRAM}-${REL}.cksum"
230 ${gpg} --detach-sign --armor "${PROGRAM}-${REL}.tar.gz"
231 ${cat} "${PROGRAM}-${REL}.tar.gz.asc" >> "${PROGRAM}-${REL}.cksum"
238 announcement_prepare() {
240 if yesno 'Prepare announcement?'; then :; else
245 if `${git} cat-file -e ${relbr}:NEWS 2>/dev/null`; then
246 ${git} show ${relbr}:NEWS > "${TMPDIR}/.${PROGRAM}-${REL}.news"
248 printf '' > "${TMPDIR}/.${PROGRAM}-${REL}.news"
251 { echo "${relmsg}"; echo; } > "${TMPDIR}/${PROGRAM}-${REL}.txt"
252 if [ -f .git/make-release.txt ]; then
254 if [ -n "${bigballs}" ] && [ -f "${TMPDIR}/${PROGRAM}-${REL}.cksum" ]
256 cks=`< "${TMPDIR}/${PROGRAM}-${REL}.cksum" \
257 ${sed} -e 's/ //' -e '/^$/,$d'`
258 < "${TMPDIR}/${PROGRAM}-${REL}.cksum" ${sed} '1,/^$/d' \
259 > "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
260 < .git/make-release.txt ${awk} \
261 -v INS="${cks}" -v SIGS="${TMPDIR}/.${PROGRAM}-${REL}.sigs" \
262 -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
263 /-----CHECKSUMS-----/{
266 for(i = 1; i <= atop; ++i){
267 match(a[i], /(\(.+\))/)
268 tfn = substr(a[i], RSTART + 1, RLENGTH - 2)
269 tpre = substr(a[i], 1, RSTART - 1)
270 tsuf = substr(a[i], RSTART + RLENGTH + 1)
271 if(fn == "" || fn != tfn)
272 printf "%s:\n", (fn = tfn)
273 printf " %6s %s\n", tpre, tsuf
277 /-----SIGNATURES-----/{
278 while(getline sl < SIGS)
283 while(getline sl < NEWS)
288 ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
289 ${rm} -f "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
291 < .git/make-release.txt ${awk} \
292 -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
294 while(getline sl < NEWS)
299 ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
301 elif [ -f "${TMPDIR}/.${PROGRAM}-${REL}.news" ]; then
302 ${cat} "${TMPDIR}/.${PROGRAM}-${REL}.news" >> \
303 "${TMPDIR}/${PROGRAM}-${REL}.txt"
306 ${rm} -f "${TMPDIR}/.${PROGRAM}-${REL}.news"
308 LC_ALL=${ORIG_LC_ALL} ${EDITOR} "${TMPDIR}/${PROGRAM}-${REL}.txt"
310 # HTML convert ready for S-Web42
312 < "${TMPDIR}/${PROGRAM}-${REL}.txt" ${awk} -v manual="${MANUAL}" '
315 print "<?begin?><?mode icewatsm?><pre>"
327 while(match(s, /(\\?https?\??:\/\/[^ ]*)/)){
328 pre = substr(s, 1, RSTART - 1)
329 mat = substr(s, RSTART, RLENGTH)
330 s = substr(s, RSTART + RLENGTH)
331 if("\\" == substr(mat, 1, 1))
335 if(match(mat, /^https\?/))
336 mat = "https" substr(xt = mat, RSTART + 6)
337 if(match(mat, /sdaoden\.eu/))
338 mat = "<?lref" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
340 mat = "<?href" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
349 /^[[:space:]]*s-.*-mode[[:space:]]*$/{
352 /^(NOTES|ChangeLog)/{
358 /^(Appendix|git\(1\) shortlog)/{
374 # Create S-Web42 local references for the possible anchors:
375 # *XY*# / $XY# / -XY# / `XY${APO}# / `~XY${APO}# / "XY"#
376 # (where the mdocmx(7) anchor follows the number sign).
377 # Ideally the anchors have been automatically expanded by
378 # make-news-anchors.sh before.
380 /(^|\(|[[:space:]]+)("[^"]+"|\*[^\*]+\*|`[^'${APO}']+'${APO}'|[-~][-#\/:_.[:alnum:]]+|\$[_[:alnum:]]+)#[0-9]+/))
382 pre = (RSTART > 1) ? substr(s, 1, RSTART - 1) : ""
383 mat = substr(s, RSTART, RLENGTH)
384 s = substr(s, RSTART + RLENGTH)
386 # Unfortunately groups are not supported
387 if(match(mat, /^(\(|[[:space:]]+)/) != 0 && RLENGTH > 0){
388 pre = pre substr(mat, 1, RLENGTH)
389 mat = substr(mat, RSTART + RLENGTH)
392 match(mat, /#[0-9]+/)
393 targ = substr(mat, RSTART + 1, RLENGTH)
394 mat = substr(mat, 1, RSTART - 1)
395 res = res pre "<?lreft " manual "#" targ "<>" mat "?>"
403 print "</pre><?end?>"
405 ' > "${TMPDIR}/.${PROGRAM}-ann.html"
409 if [ -n "${bigballs}" ] && yesno 'Upload archives'; then :; else
415 echo "-put ${PROGRAM}-${REL}.tar.xz"
416 echo "-rm ${PROGRAM}-latest.tar.xz"
417 echo "-ln -s ${PROGRAM}-${REL}.tar.xz ${PROGRAM}-latest.tar.xz"
419 echo "-put ${PROGRAM}-${REL}.tar.xz.asc"
420 echo "-rm ${PROGRAM}-latest.tar.xz.asc"
421 echo "-ln -s ${PROGRAM}-${REL}.tar.xz.asc ${PROGRAM}-latest.tar.xz.asc"
423 echo "-put ${PROGRAM}-${REL}.tar.gz"
424 echo "-rm ${PROGRAM}-latest.tar.gz"
425 echo "-ln -s ${PROGRAM}-${REL}.tar.gz ${PROGRAM}-latest.tar.gz"
427 echo "-put ${PROGRAM}-${REL}.tar.gz.asc"
428 echo "-rm ${PROGRAM}-latest.tar.gz.asc"
429 echo "-ln -s ${PROGRAM}-${REL}.tar.gz.asc ${PROGRAM}-latest.tar.gz.asc"
431 if [ -n "${anntxt}" ]; then
432 echo "-put ${PROGRAM}-${REL}.txt"
433 echo "-rm ${PROGRAM}-latest.txt"
434 echo "-ln -s ${PROGRAM}-${REL}.txt ${PROGRAM}-latest.txt"
437 echo "-chmod 0644 ${PROGRAM}-${REL}.*"
439 ${sftp} -b - ${UPLOAD}
442 announcement_send() {
443 if [ -n "${anntxt}" ] && yesno 'Send announcement mail?'; then
444 LC_ALL=${ORIG_LC_ALL} ${MAILX} -A ${ACCOUNT} \
445 -s "[ANN]ounce of ${UPROGRAM} v${REL}${RELSYM}" \
446 -q "${TMPDIR}/${PROGRAM}-${REL}.txt" \
447 -b ${MAILBCC} ${MAILTO}
451 create_grappa_env() {
452 echo 'Updating files: calling update_release_hook'
454 echo 'E allora io quasi quasi prendo il treno'
458 if [ ${#} -ne 0 ]; then
459 if [ ${#} != 2 ] || [ "${1}" != grappa ] || [ -z "${2}" ]; then
460 echo >&2 'You have a hell of a lot to learn about Rock'"'"'n Roll'
467 echo 'Preparing a release on commit '"${headref}"
468 if [ -z "${grappa}" ]; then
469 printf ' The HEAD is %s\nName of release tag: ' "${brname}"
476 echo 'Grappa to be brought from '"${brname}"' to '"${grappa}"
478 printf 'Program version is %s, packager release addition shall be: ' \
481 VERSION="${VERSION}-${REL}"
485 if ${git} rev-parse --verify ${grappa} >/dev/null 2>/dev/null; then :; else
488 ${git} checkout ${i} ${grappa}
490 ${git} archive --format=tar ${headref} | ${tar} -x -f -
494 echo 'Updating files: calling update_stable_hook'
497 if [ -z "${grappa}" ]; then
499 create_release_branch
500 check_timeline_branch
511 # Finally remove the temporary instances than ran this
512 ${rm} -f .git/make-release.*