make-config.in: complete path (leftover of [807f64e2], 2015-12-26!)
[s-mailx.git] / make-release.inc
blob28d7cf0d982525501212fbf0ba6bf6e572479d9c
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.
16 : ${MAILX:=mailx}
17 : ${ACCOUNT:?"May need mailx(1) -A \$ACCOUNT"}
18 : ${MAILTO:?"May need \$MAILTO for announcement"}
19 : ${MAILBCC:?"May need \$MAILBCC for announcement"}
21 # Program stuff
22 : ${awk:=awk}
23 : ${cat:=cat}
24 : ${cmp:=cmp}
25 : ${date:=date}
26 : ${git:=git}
27 : ${grep:=grep}
28 : ${make:=make}
29 : ${mv:=mv}
30 : ${SHELL:=sh}
31 : ${sed:=sed}
33 # non-grappa only
34 : ${gzip:=gzip}
35 : ${openssl:=openssl}
36 : ${pgp:=pgp}
37 : ${rm:=rm}
38 : ${sftp:=sftp}
39 : ${tar:=tar}
40 : ${xz:=xz}
42 ##  --  >8  --  8<  --  ##
44 ORIG_LC_ALL=${LC_ALL} LC_ALL=C
45 export LC_ALL
47 DATE_MAN=`${date} -u +'%B %d, %Y'`
48 DATE_ISO=`${date} -u +%Y-%m-%d`
50 yesno() {
51    while [ 1 ]; do
52       [ ${#} -gt 0 ] && printf '%s ' "${@}"
53       printf '[y/n] '
54       read i
55       case ${i} in
56       [Yy]*) return 0;;
57       [Nn]*) return 1;;
58       *) ;;
59       esac
60    done
63 ref_status() {
64    headref="`${git} rev-parse --verify HEAD`"
65    brref=
66    for i in `${git} rev-parse --branches=stable master^{commit}`; do
67       if [ ${headref} = ${i} ]; then
68          brref=${headref}
69          break
70       fi
71    done
72    if [ -z "${brref}" ]; then
73       echo >&2 'Not on the [master] or a [stable/*] branch'
74       exit 1
75    fi
76    if [ "`${git} status --porcelain --ignored |
77          ${awk} 'BEGIN{no=0}{++no}END{print no}'`" -ne 0 ]; then
78       echo >&2 'Directory not clean, see git status --ignored'
79       exit 2
80    fi
81    #brname="`git branch | sed -e '/^* /b X' -e d -e :X -e 's/^* //'`"
82    brname=`${git} symbolic-ref --short HEAD`
85 release_version() {
86    vmaj=`{ echo ${VERSION}; } | ${sed} -e 's/^\([^.]\{1,\}\).*/\1/'`
87    vmin=`{ echo ${VERSION}; } |
88       ${sed} -e 's/^[^.]\{1,\}\.\([^.]\{1,\}\).*/\1/'`
89    [ ${vmin} = ${VERSION} ] && VERSION=${VERSION}.0 vmin=0
90    vupd=`{ echo ${VERSION}; } |
91          ${sed} -e 's/^[^.]\{1,\}\.[^.]\{1,\}\.\([^.-]\{1,\}\).*/\1/'`
92    [ ${vupd} = ${VERSION} ] && VERSION=${VERSION}.0 vupd=0
93    REL=${VERSION}
94    export VERSION
95    if yesno 'Is '${PROGRAM}' <v'${REL}'> correct?'; then :; else
96       echo >&2 'Bailing out'
97       exit 3
98    fi
101 release_brcheck() {
102    stblbrname=stable/v${vmaj}.${vmin} need_stblbrname=
103    brref=`${git} rev-parse --verify ${stblbrname} 2>/dev/null`
104    if [ -z "${brref}" ]; then
105       if yesno 'Create new branch '"${stblbrname}"' after release tag'; then
106          need_stblbrname=1
107       fi
108    elif [ ${brref} != ${headref} ] || [ ${brname} != ${stblbrname} ]; then
109       echo >&2 "For ${REL} we should be on ${stblbrname}, not ${brname}"
110       echo >&2 'Bailing out'
111       exit 4
112    fi
114    relbrname=release/v${VERSION}
115    brref=`${git} rev-parse --verify ${relbrname} 2>/dev/null`
116    if [ -z "${brref}" ]; then :; else
117       echo >&2 "The ${relbrname} already exists"
118       echo >&2 'Bailing out'
119       exit 5
120    fi
123 release_symname() {
124    RELSYM=
125    stblmsg= relmsg=
126    if yesno 'Shall '${PROGRAM}' v'${REL}' have a symbolic name?'; then
127       printf '  ..and it shall be known as: '
128       read RELSYM
129       if yesno 'Is '"${RELSYM}"' correct?'; then :; else
130          echo >&2 'Bailing out'
131          exit 3
132       fi
133       stblmsg="Bump ${UPROGRAM} v${REL} (\"${RELSYM}\"), ${DATE_ISO}"
134       relmsg="Bump ${UPROGRAM} v${REL}.ar (\"${RELSYM}\"), ${DATE_ISO}"
135       RELSYM=" (\"${RELSYM}\")"
136    else
137       stblmsg="Bump ${UPROGRAM} v${REL}, ${DATE_ISO}"
138       relmsg="Bump ${UPROGRAM} v${REL}.ar, ${DATE_ISO}"
139    fi
142 update_stable_branch() {
143    LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${stblmsg}"
144    LC_ALL=${ORIG_LC_ALL} ${git} tag -s -f -m "${stblmsg}" v${REL}
146    if [ -n "${need_stblbrname}" ]; then
147       ${git} checkout -b ${stblbrname}
148    fi
149    # Normally done in post-commit hook, but not once initially created
150    if yesno 'Shall i update stable/latest "symlink"?'; then
151       ${git} update-ref refs/heads/stable/latest ${stblbrname}
152    fi
153    if yesno 'Shall i update stable/stable "symlink"?'; then
154       ${git} update-ref refs/heads/stable/stable ${stblbrname}
155    fi
158 create_release_branch() {
159    if yesno 'Create release/ branch?'; then
160       ${git} checkout -b ${relbrname}
162       echo 'Updating files: calling update_release_hook'
163       update_release_hook
165       LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${relmsg}"
166       LC_ALL=${ORIG_LC_ALL} ${git} tag -s -f -m "${relmsg}" v${REL}.ar
168       if yesno 'Shall i update release/latest "symlink"?'; then
169          ${git} update-ref refs/heads/release/latest ${relbrname}
170       fi
171       if yesno 'Shall i update release/stable "symlink"?'; then
172          ${git} update-ref refs/heads/release/stable ${relbrname}
173       fi
174    else
175       relbrname=${stblbrname}
176    fi
179 check_timeline_branch() {
180    if [ ${relbrname} != ${stblbrname} ] &&
181          `${git} rev-parse --verify timeline^{commit} >/dev/null 2>&1` &&
182          yesno 'Shall i update [timeline]?'; then
183       ${git} checkout timeline
184       ${git} rm -rf '*'
185       ${git} archive --format=tar "v${REL}.ar" | ${tar} -x -f -
186       ${git} add .
187       LC_ALL=${ORIG_LC_ALL} ${git} commit -S -n -m "${relmsg}"
188    fi
191 repo_push() {
192    [ ${relbrname} != ${stblbrname} ] && ${git} checkout ${stblbrname}
193    ${git} log --no-walk --decorate --oneline --branches --remotes
194    yesno 'Push git(1) repo?' && ${git} push
197 big_balls() {
198    if [ ${relbrname} != ${stblbrname} ] && yesno 'Create tarballs?'; then
199       bigballs=y
200       (
201       umask 0022
203       # Repack with standard tar(1) to avoid new-style headers
204       ${git} archive --format=tar --prefix="${PROGRAM}-${REL}/" v${REL}.ar |
205          ( cd "${TMPDIR}" && ${tar} -x -f - )
206       cd "${TMPDIR}"
208       ${tar} -c -f "${PROGRAM}-${REL}.tar" "${PROGRAM}-${REL}"
209       < "${PROGRAM}-${REL}.tar" ${xz} -e -C sha256 > "${PROGRAM}-${REL}.tar.xz"
210       < "${PROGRAM}-${REL}.tar" ${gzip} > "${PROGRAM}-${REL}.tar.gz"
211       ${rm} "${PROGRAM}-${REL}.tar"
213       printf '' > "${PROGRAM}-${REL}.cksum"
214       ${openssl} sha1 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
215       ${openssl} sha256 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
216       ${openssl} sha512 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
217       ${openssl} sha1 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
218       ${openssl} sha256 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
219       ${openssl} sha512 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
221       echo >> "${PROGRAM}-${REL}.cksum"
222       ${gpg} --detach-sign --armor "${PROGRAM}-${REL}.tar.xz"
223       ${cat} "${PROGRAM}-${REL}.tar.xz.asc" >> "${PROGRAM}-${REL}.cksum"
224       ${gpg} --detach-sign --armor "${PROGRAM}-${REL}.tar.gz"
225       ${cat} "${PROGRAM}-${REL}.tar.gz.asc" >> "${PROGRAM}-${REL}.cksum"
226       )
227    else
228       bigballs=
229    fi
232 announcement_prepare() {
233    anntxt=
234    if yesno 'Prepare announcement?'; then :; else
235       return
236    fi
237    anntxt=y
239    if `${git} cat-file -e ${relbr}:NEWS 2>/dev/null`; then
240       ${git} show ${relbr}:NEWS > "${TMPDIR}/.${PROGRAM}-${REL}.news"
241    else
242       printf '' > "${TMPDIR}/.${PROGRAM}-${REL}.news"
243    fi
245    { echo "${relmsg}"; echo; } > "${TMPDIR}/${PROGRAM}-${REL}.txt"
246    if [ -f .git/make-release.txt ]; then
247       # For the checksums
248       if [ -n "${bigballs}" ] && [ -f "${TMPDIR}/${PROGRAM}-${REL}.cksum" ]
249       then
250          cks=`< "${TMPDIR}/${PROGRAM}-${REL}.cksum" \
251                ${sed} -e 's/ //' -e '/^$/,$d'`
252          < "${TMPDIR}/${PROGRAM}-${REL}.cksum" ${sed} '1,/^$/d' \
253             > "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
254          < .git/make-release.txt ${awk} \
255                -v INS="${cks}" -v SIGS="${TMPDIR}/.${PROGRAM}-${REL}.sigs" \
256                -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
257             /-----CHECKSUMS-----/{
258                atop = split(INS, a)
259                fn = ""
260                for(i = 1; i <= atop; ++i){
261                   match(a[i], /(\(.+\))/)
262                   tfn = substr(a[i], RSTART + 1, RLENGTH - 2)
263                   tpre = substr(a[i], 1, RSTART - 1)
264                   tsuf = substr(a[i], RSTART + RLENGTH + 1)
265                   if(fn == "" || fn != tfn)
266                      printf "%s:\n", (fn = tfn)
267                   printf "  %6s %s\n", tpre, tsuf
268                }
269                next
270             }
271             /-----SIGNATURES-----/{
272                while(getline sl < SIGS)
273                   print sl
274                next
275             }
276             /-----NEWS-----/{
277                while(getline sl < NEWS)
278                   print sl
279                next
280             }
281             {print}
282          ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
283          ${rm} -f "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
284       else
285          < .git/make-release.txt ${awk} \
286                -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
287             /-----NEWS-----/{
288                while(getline sl < NEWS)
289                   print sl
290                next
291             }
292             {print}
293          ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
294       fi
295    elif [ -f "${TMPDIR}/.${PROGRAM}-${REL}.news" ]; then
296       ${cat} "${TMPDIR}/.${PROGRAM}-${REL}.news" >> \
297          "${TMPDIR}/${PROGRAM}-${REL}.txt"
298    fi
300    ${rm} -f "${TMPDIR}/.${PROGRAM}-${REL}.news"
302    LC_ALL=${ORIG_LC_ALL} ${EDITOR} "${TMPDIR}/${PROGRAM}-${REL}.txt"
304    # HTML convert ready for S-Web42
305    APO=\'
306    < "${TMPDIR}/${PROGRAM}-${REL}.txt" ${awk} -v manual="${MANUAL}" '
307    BEGIN{
308       hot = 0
309       print "<?begin?><?mode icewatsm?><pre>"
310    }
311    function strips(){
312       gsub("&", "\\&amp;")
313       gsub("<", "\\&lt;")
314       gsub(">", "\\&gt;")
315    }
316    function urls(){
317       any = 0
318       res = ""
319       s = $0
321       while(match(s, /(\\?https?\??:\/\/[^ ]*)/)){
322          pre = substr(s, 1, RSTART - 1)
323          mat = substr(s, RSTART, RLENGTH)
324          s = substr(s, RSTART + RLENGTH)
325          if("\\" == substr(mat, 1, 1))
326             mat = substr(mat, 2)
327          else{
328             xt = 0
329             if(match(mat, /^https\?/))
330                mat = "https" substr(xt = mat, RSTART + 6)
331             if(match(mat, /sdaoden\.eu/))
332                mat = "<?lref" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
333             else
334                mat = "<?href" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
335          }
336          res = res pre mat
337          any = 1
338       }
339       if(any && length(s))
340          res = res s
341       $0 = any ? res : s
342    }
343    /^[[:space:]]*s-.*-mode[[:space:]]*$/{
344       exit 0
345    }
346    /^(NOTES|ChangeLog)/{
347       hot = 1
348       strips()
349       print
350       next
351    }
352    /^(Appendix|git\(1\) shortlog)/{
353       hot = -1
354       strips()
355       print
356       next
357    }
358    {
359       strips()
360       urls()
361       if(hot <= 0){
362          print
363          next
364       }
365       any = 0
366       res = ""
367       s = $0
368       # Create S-Web42 local references for the possible anchors:
369       #     *XY*# / $XY# / -XY# / `XY${APO}# / `~XY${APO}# / "XY"#
370       # (where the mdocmx(7) anchor follows the number sign).
371       # Ideally the anchors have been automatically expanded by
372       # make-news-anchors.sh before.
373       while(match(s,
374             /(^|\(|[[:space:]]+)("[^"]+"|\*[^\*]+\*|`[^'${APO}']+'${APO}'|[-~][-#\/:_.[:alnum:]]+|\$[_[:alnum:]]+)#[0-9]+/))
375       {
376          pre = (RSTART > 1) ? substr(s, 1, RSTART - 1) : ""
377          mat = substr(s, RSTART, RLENGTH)
378          s = substr(s, RSTART + RLENGTH)
380          # Unfortunately groups are not supported
381          if(match(mat, /^(\(|[[:space:]]+)/) != 0 && RLENGTH > 0){
382             pre = pre substr(mat, 1, RLENGTH)
383             mat = substr(mat, RSTART + RLENGTH)
384          }
386          match(mat, /#[0-9]+/)
387          targ = substr(mat, RSTART + 1, RLENGTH)
388          mat = substr(mat, 1, RSTART - 1)
389          res = res pre "<?lreft " manual "#" targ "<>" mat "?>"
390          any = 1
391       }
392       if(any && length(s))
393          res = res s
394       print any ? res : s
395    }
396    END{
397       print "</pre><?end?>"
398    }
399    ' > "${TMPDIR}/.${PROGRAM}-ann.html"
402 upload() (
403    if [ -n "${bigballs}" ] && yesno 'Upload archives'; then :; else
404       return
405    fi
406    cd "${TMPDIR}"
408    {
409       echo "-put ${PROGRAM}-${REL}.tar.xz"
410       echo "-rm ${PROGRAM}-latest.tar.xz"
411       echo "-ln -s ${PROGRAM}-${REL}.tar.xz ${PROGRAM}-latest.tar.xz"
413       echo "-put ${PROGRAM}-${REL}.tar.xz.asc"
414       echo "-rm ${PROGRAM}-latest.tar.xz.asc"
415       echo "-ln -s ${PROGRAM}-${REL}.tar.xz.asc ${PROGRAM}-latest.tar.xz.asc"
417       echo "-put ${PROGRAM}-${REL}.tar.gz"
418       echo "-rm ${PROGRAM}-latest.tar.gz"
419       echo "-ln -s ${PROGRAM}-${REL}.tar.gz ${PROGRAM}-latest.tar.gz"
421       echo "-put ${PROGRAM}-${REL}.tar.gz.asc"
422       echo "-rm ${PROGRAM}-latest.tar.gz.asc"
423       echo "-ln -s ${PROGRAM}-${REL}.tar.gz.asc ${PROGRAM}-latest.tar.gz.asc"
425       if [ -n "${anntxt}" ]; then
426          echo "-put ${PROGRAM}-${REL}.txt"
427          echo "-rm ${PROGRAM}-latest.txt"
428          echo "-ln -s ${PROGRAM}-${REL}.txt ${PROGRAM}-latest.txt"
429       fi
431       echo "-chmod 0644 ${PROGRAM}-${REL}.*"
432    } |
433    ${sftp} -b - ${UPLOAD}
436 announcement_send() {
437    if [ -n "${anntxt}" ] && yesno 'Send announcement mail?'; then
438       LC_ALL=${ORIG_LC_ALL} ${MAILX} -A ${ACCOUNT} \
439          -s "[ANN]ounce of ${UPROGRAM} v${REL}${RELSYM}" \
440          -q "${TMPDIR}/${PROGRAM}-${REL}.txt" \
441          -b ${MAILBCC} ${MAILTO}
442    fi
445 create_grappa_env() {
446    echo 'Updating files: calling update_release_hook'
447    update_release_hook
448    echo 'E allora io quasi quasi prendo il treno'
451 grappa=
452 if [ ${#} -ne 0 ]; then
453    if [ ${#} != 2 ] || [ "${1}" != grappa ] || [ -z "${2}" ]; then
454       echo >&2 'You have a hell of a lot to learn about Rock'"'"'n Roll'
455       exit 55
456    fi
457    grappa=${2}
460 ref_status
461 echo 'Preparing a release on commit '"${headref}"
462 if [ -z "${grappa}" ]; then
463    printf '  The HEAD is %s\nName of release tag: ' "${brname}"
464    read REL
465    VERSION=${REL}
466    release_version
467    release_brcheck
468    release_symname
469 else
470    echo 'Grappa to be brought from '"${brname}"' to '"${grappa}"
471    current_version
472    printf 'Program version is %s, packager release addition shall be: ' \
473       "${VERSION}"
474    read REL
475    VERSION="${VERSION}-${REL}"
476    release_version
478    i=
479    if ${git} rev-parse --verify ${grappa} >/dev/null 2>/dev/null; then :; else
480       i=-B
481    fi
482    ${git} checkout ${i} ${grappa}
483    ${git} rm -f '*'
484    ${git} archive --format=tar ${headref} | ${tar} -x -f -
485    ${git} add .
488 echo 'Updating files: calling update_stable_hook'
489 update_stable_hook
491 if [ -z "${grappa}" ]; then
492    update_stable_branch
493    create_release_branch
494    check_timeline_branch
495    repo_push
496    big_balls
497    announcement_prepare
498    upload
499    announcement_send
500 else
501    create_grappa_env
505 # Finally remove the temporary instances than ran this
506 ${rm} -f .git/make-release.*
507 echo 'Done'
508 exit
509 # s-sh-mode