README: Add "Security record" section
[s-mailx.git] / mk-release.inc
bloba7c88a8b3b53f5778c0a50fab706af4afab2ae9c
1 #@ Include file for the mk-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.
5 : ${PROGRAM:?"Need \$PROGRAM"}
6 : ${UPROGRAM:?"Need \$UPROGRAM"}
7 : ${MANUAL:?"May need \$MANUAL for announcement references"}
9 : ${UPLOAD:?"Need \$UPLOAD URL for scp(1)"}
11 : ${MAILX:=mailx}
12 : ${ACCOUNT:?"May need mailx(1) -A \$ACCOUNT"}
13 : ${MAILTO:?"May need \$MAILTO for announcement"}
14 : ${MAILBCC:?"May need \$MAILBCC for announcement"}
16 ##  --  >8  --  8<  --  ##
18 ORIG_LC_ALL=${LC_ALL} LC_ALL=C
19 export LC_ALL
21 DATE_MAN=`date -u +'%B %d, %Y'`
22 DATE_ISO=`date -u +%Y-%m-%d`
24 yesno() {
25    while [ 1 ]; do
26       [ ${#} -gt 0 ] && printf '%s ' "${@}"
27       printf '[y/n] '
28       read i
29       case ${i} in
30       [Yy]*) return 0;;
31       [Nn]*) return 1;;
32       *) ;;
33       esac
34    done
37 headref="`git rev-parse --verify HEAD`"
38 brref=
39 for i in `git rev-parse --branches=stable master^{commit}`; do
40    if [ ${headref} = ${i} ]; then
41       brref=${headref}
42       break
43    fi
44 done
45 if [ -z "${brref}" ]; then
46    echo >&2 'Not on the [master] or a [stable/*] branch'
47    exit 1
49 if [ "`git status --porcelain --ignored |
50       awk 'BEGIN{no=0}{++no}END{print no}'`" -ne 0 ]; then
51    echo >&2 'Directory not clean, see git status --ignored'
52    exit 2
55 echo 'Preparing a release on commit '"${headref}"
56 #brname="`git branch | sed -e '/^* /b X' -e d -e :X -e 's/^* //'`"
57 brname=`git symbolic-ref --short HEAD`
58 echo '  That is '"${brname}"
59 printf '  Name of release tag: '
60 read REL
61 VERSION=${REL}
62 vmaj=`{ echo ${VERSION}; } | sed -e 's/^\([^.]\{1,\}\).*/\1/'`
63 vmin=`{ echo ${VERSION}; } | sed -e 's/^[^.]\{1,\}\.\([^.]\{1,\}\).*/\1/'`
64 [ ${vmin} = ${VERSION} ] && VERSION=${VERSION}.0 vmin=0
65 vupd=`{ echo ${VERSION}; } |
66       sed -e 's/^[^.]\{1,\}\.[^.]\{1,\}\.\([^.-]\{1,\}\).*/\1/'`
67 [ ${vupd} = ${VERSION} ] && VERSION=${VERSION}.0 vupd=0
68 REL=${VERSION}
69 export VERSION
70 if yesno 'Is '${PROGRAM}' <v'${REL}'> correct?'; then :; else
71    echo >&2 'Bailing out'
72    exit 3
75 stblbrname=stable/v${vmaj}.${vmin}
76 brref=`git rev-parse --verify ${stblbrname} 2>/dev/null`
77 if [ -z "${brref}" ]; then
78    if yesno 'Create and switch to new branch '"${stblbrname}"; then
79       git checkout -b ${stblbrname}
80    fi
81 elif [ ${brref} != ${headref} ] || [ ${brname} != ${stblbrname} ]; then
82    echo >&2 "For ${REL} we should be on ${stblbrname}, not ${brname}"
83    echo >&2 'Bailing out'
84    exit 4
87 relbrname=release/v${VERSION}
88 brref=`git rev-parse --verify ${relbrname} 2>/dev/null`
89 if [ -z "${brref}" ]; then :; else
90    echo >&2 "The ${relbrname} already exists"
91    echo >&2 'Bailing out'
92    exit 5
95 RELSYM=
96 stblmsg= relmsg=
97 if yesno 'Shall '${PROGRAM}' v'${REL}' have a symbolic name?'; then
98    printf '  ..and it shall be known as: '
99    read RELSYM
100    if yesno 'Is '"${RELSYM}"' correct?'; then :; else
101       echo >&2 'Bailing out'
102       exit 3
103    fi
104    stblmsg="Bump ${UPROGRAM} v${REL} (\"${RELSYM}\"), ${DATE_ISO}"
105    relmsg="Bump ${UPROGRAM} v${REL}.ar (\"${RELSYM}\"), ${DATE_ISO}"
106    RELSYM=" (\"${RELSYM}\")"
107 else
108    stblmsg="Bump ${UPROGRAM} v${REL}, ${DATE_ISO}"
109    relmsg="Bump ${UPROGRAM} v${REL}.ar, ${DATE_ISO}"
113 echo 'Updating stable/ files to match the release'
115 if [ -f version.h ] && [ -f mk-mk.in ]; then
116    grep=grep sed=sed cmp=cmp mv=mv make -f mk-mk.in _update-version
117    git add version.h
119 update_stable_hook
121 LC_ALL=${ORIG_LC_ALL} git commit -S -m "${stblmsg}"
122 LC_ALL=${ORIG_LC_ALL} git tag -s -f -m "${stblmsg}" v${REL}
126 if yesno 'Create release/ branch?'; then
127    git checkout -b ${relbrname}
129    git rm -f .gitignore .mailmap TODO mk-release.*
130    update_release_hook
132    LC_ALL=${ORIG_LC_ALL} git commit -S -m "${relmsg}"
133    LC_ALL=${ORIG_LC_ALL} git tag -s -f -m "${relmsg}" v${REL}.ar
135    if yesno 'Shall i update release/latest "symlink"?'; then
136       git update-ref refs/heads/release/latest ${relbrname}
137    fi
138    if yesno 'Shall i update release/stable "symlink"?'; then
139       git update-ref refs/heads/release/stable ${relbrname}
140    fi
141 else
142    relbrname=${stblbrname}
146 # [timeline]
148 if [ ${relbrname} != ${stblbrname} ] &&
149       `git rev-parse --verify timeline^{commit} >/dev/null 2>&1` &&
150       yesno 'Shall i update [timeline]?'; then
151    git checkout timeline
152    git rm -rf '*'
153    git archive --format=tar "v${REL}.ar" | tar -x -f -
154    git add .
155    LC_ALL=${ORIG_LC_ALL} git commit -S -m "${relmsg}"
159 # repo push
161 [ ${relbrname} != ${stblbrname} ] && git checkout ${stblbrname}
162 git log --no-walk --decorate --oneline --branches --remotes
163 yesno 'Push git(1) repo?' && git push
166 # Big balls
168 if [ ${relbrname} != ${stblbrname} ] && yesno 'Create tarballs?'; then
169    bigballs=y
170    (
171    # Repack with standard tar(1) to avoid new-style headers
172    git archive --format=tar --prefix="${PROGRAM}-${REL}/" v${REL}.ar |
173       ( cd "${TMPDIR}" && tar -x -f - )
174    cd "${TMPDIR}"
176    tar -c -f "${PROGRAM}-${REL}.tar" "${PROGRAM}-${REL}"
177    < "${PROGRAM}-${REL}.tar" xz -e -C sha256 > "${PROGRAM}-${REL}.tar.xz"
178    < "${PROGRAM}-${REL}.tar" gzip > "${PROGRAM}-${REL}.tar.gz"
179    rm "${PROGRAM}-${REL}.tar"
181    : > "${PROGRAM}-${REL}.cksum"
182    openssl sha1 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
183    openssl sha256 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
184    openssl sha512 "${PROGRAM}-${REL}.tar.xz" >> "${PROGRAM}-${REL}.cksum"
185    openssl sha1 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
186    openssl sha256 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
187    openssl sha512 "${PROGRAM}-${REL}.tar.gz" >> "${PROGRAM}-${REL}.cksum"
189    echo >> "${PROGRAM}-${REL}.cksum"
190    gpg --detach-sign --armor "${PROGRAM}-${REL}.tar.xz"
191    cat "${PROGRAM}-${REL}.tar.xz.asc" >> "${PROGRAM}-${REL}.cksum"
192    gpg --detach-sign --armor "${PROGRAM}-${REL}.tar.gz"
193    cat "${PROGRAM}-${REL}.tar.gz.asc" >> "${PROGRAM}-${REL}.cksum"
194    )
195 else
196    bigballs=
200 # Announcement .txt and .html
202 if yesno 'Prepare announcement?'; then
203    anntxt=y
205    if `git cat-file -e ${relbr}:NEWS 2>/dev/null`; then
206       git show ${relbr}:NEWS > "${TMPDIR}/.${PROGRAM}-${REL}.news"
207    else
208       : > "${TMPDIR}/.${PROGRAM}-${REL}.news"
209    fi
211    { echo "${relmsg}"; echo; } > "${TMPDIR}/${PROGRAM}-${REL}.txt"
212    if [ -f .git/mk-release.txt ]; then
213       # For the checksums
214       if [ -n "${bigballs}" ] && [ -f "${TMPDIR}/${PROGRAM}-${REL}.cksum" ]
215       then
216          cks=`< "${TMPDIR}/${PROGRAM}-${REL}.cksum" sed -e 's/ //' -e '/^$/,$d'`
217          < "${TMPDIR}/${PROGRAM}-${REL}.cksum" sed '1,/^$/d' \
218             > "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
219          < .git/mk-release.txt awk \
220                -v INS="${cks}" -v SIGS="${TMPDIR}/.${PROGRAM}-${REL}.sigs" \
221                -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
222             /-----CHECKSUMS-----/{
223                atop = split(INS, a)
224                fn = ""
225                for(i = 1; i <= atop; ++i){
226                   match(a[i], /(\(.+\))/)
227                   tfn = substr(a[i], RSTART + 1, RLENGTH - 2)
228                   tpre = substr(a[i], 1, RSTART - 1)
229                   tsuf = substr(a[i], RSTART + RLENGTH + 1)
230                   if(fn == "" || fn != tfn)
231                      printf "%s:\n", (fn = tfn)
232                   printf "  %6s %s\n", tpre, tsuf
233                }
234                next
235             }
236             /-----SIGNATURES-----/{
237                while(getline sl < SIGS)
238                   print sl
239                next
240             }
241             /-----NEWS-----/{
242                while(getline sl < NEWS)
243                   print sl
244                next
245             }
246             {print}
247          ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
248          rm -f "${TMPDIR}/.${PROGRAM}-${REL}.sigs"
249       else
250          < .git/mk-release.txt awk \
251                -v NEWS="${TMPDIR}/.${PROGRAM}-${REL}.news" '
252             /-----NEWS-----/{
253                while(getline sl < NEWS)
254                   print sl
255                next
256             }
257             {print}
258          ' >> "${TMPDIR}/${PROGRAM}-${REL}.txt"
259       fi
260    elif [ -f "${TMPDIR}/.${PROGRAM}-${REL}.news" ]; then
261       cat "${TMPDIR}/.${PROGRAM}-${REL}.news" >> \
262          "${TMPDIR}/${PROGRAM}-${REL}.txt"
263    fi
265    rm -f "${TMPDIR}/.${PROGRAM}-${REL}.news"
267    LC_ALL=${ORIG_LC_ALL} ${EDITOR} "${TMPDIR}/${PROGRAM}-${REL}.txt"
269    # HTML convert ready for S-Web42
270    APO=\'
271    < "${TMPDIR}/${PROGRAM}-${REL}.txt" awk -v manual="${MANUAL}" '
272    BEGIN{
273       header = 1
274       hot = 0
275       print "<?begin?><?mode icewatsm?><pre>"
276    }
277    function strips(){
278       gsub("&", "\\&amp;")
279       gsub("<", "\\&lt;")
280       gsub(">", "\\&gt;")
281    }
282    function urls(){
283       any = 0
284       res = ""
285       s = $0
287       while(match(s, /(\\?(http|ftp)s?\??:\/\/[^ ]*)/)){
288          pre = substr(s, 1, RSTART - 1)
289          mat = substr(s, RSTART, RLENGTH)
290          s = substr(s, RSTART + RLENGTH)
291          if("\\" == substr(mat, 1, 1))
292             mat = substr(mat, 2)
293          else{
294             xt = 0
295             if(match(mat, /^https\?/))
296                mat = "https" substr(xt = mat, RSTART + 6)
297             else if(match(mat, /^ftps\?/))
298                mat = "ftps" substr(xt = mat, RSTART + 5)
299             if(match(mat, /sdaoden\.eu/))
300                mat = "<?lref" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
301             else
302                mat = "<?href" (xt ? "t " : " ") mat (xt ? "<>" xt : "") "?>"
303          }
304          res = res pre mat
305          any = 1
306       }
307       if(any && length(s))
308          res = res s
309       $0 = any ? res : s
310    }
311    /^[[:space:]]*s-.*-mode[[:space:]]*$/{
312       header = 1
313       next
314    }
315    /ChangeLog|shortlog/{
316       if(header)
317          next
318       if(hot == 0)
319          hot = 1
320       strips()
321    }
322    /Appendix/{
323       if(header)
324          next
325       hot = -1
326       strips()
327    }
328    {
329       if(header){
330          if(length == 0)
331             header = 0
332          next
333       }
334       strips()
335       urls()
336       if(hot <= 0){
337          print
338          next
339       }
340       any = 0
341       res = ""
342       s = $0
343       while(match(s,
344             /("[^"]+"|\*[^\*]+\*|`[^'${APO}']+'${APO}'|[-~][-\/:_.[:alnum:]]+|\$[_[:alnum:]]+)#[0-9]+(\|#_?[0-9]+)?/))
345       {
346          pre = substr(s, 1, RSTART - 1)
347          mat = substr(s, RSTART, RLENGTH)
348          s = substr(s, RSTART + RLENGTH)
350          if(match(mat, /\|#_?[0-9]+/)){
351             targ = substr(mat, RSTART + 2)
352             mat = substr(mat, 1, RSTART - 1)
353          }else{
354             match(mat, /#[0-9]+/)
355             targ = substr(mat, RSTART + 1, RLENGTH)
356          }
357          res = res pre "<?lreft " manual "#" targ "<>" mat "?>"
358          any = 1
359       }
360       if(any && length(s))
361          res = res s
362       print any ? res : s
363    }
364    END{
365       print "</pre><?end?>"
366    }
367    ' > "${TMPDIR}/.${PROGRAM}-ann.html"
368 else
369    anntxt=
373 # Upload
375 if [ -n "${bigballs}" ] && yesno 'Upload archives'; then
376    (
377    cd "${TMPDIR}"
379    {
380       echo "-put ${PROGRAM}-${REL}.tar.xz"
381       echo "-rm ${PROGRAM}-latest.tar.xz"
382       echo "-ln -s ${PROGRAM}-${REL}.tar.xz ${PROGRAM}-latest.tar.xz"
384       echo "-put ${PROGRAM}-${REL}.tar.xz.asc"
385       echo "-rm ${PROGRAM}-latest.tar.xz.asc"
386       echo "-ln -s ${PROGRAM}-${REL}.tar.xz.asc ${PROGRAM}-latest.tar.xz.asc"
388       echo "-put ${PROGRAM}-${REL}.tar.gz"
389       echo "-rm ${PROGRAM}-latest.tar.gz"
390       echo "-ln -s ${PROGRAM}-${REL}.tar.gz ${PROGRAM}-latest.tar.gz"
392       echo "-put ${PROGRAM}-${REL}.tar.gz.asc"
393       echo "-rm ${PROGRAM}-latest.tar.gz.asc"
394       echo "-ln -s ${PROGRAM}-${REL}.tar.gz.asc ${PROGRAM}-latest.tar.gz.asc"
396       if [ -n "${anntxt}" ]; then
397          echo "-put ${PROGRAM}-${REL}.txt"
398          echo "-rm ${PROGRAM}-latest.txt"
399          echo "-ln -s ${PROGRAM}-${REL}.txt ${PROGRAM}-latest.txt"
400       fi
402       echo "-chmod 0644 ${PROGRAM}-${REL}.*"
403    } |
404    sftp -b - ${UPLOAD}
405    )
409 # Announcement mail
411 if [ -n "${anntxt}" ] && yesno 'Send announcement mail?'; then
412    LC_ALL=${ORIG_LC_ALL} ${MAILX} -A ${ACCOUNT} \
413       -s "[ANN]ounce of ${UPROGRAM} v${REL}${RELSYM}" \
414       -q "${TMPDIR}/${PROGRAM}-${REL}.txt" \
415       -b ${MAILBCC} ${MAILTO}
418 # Finally remove the temporary instances than ran this
419 rm -f .git/mk-release.*
420 echo 'Done'
421 exit
422 # s-sh-mode