scripts/mk-release.sh
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Mar 14 12:12:10 2010 +0100 (2010-03-14)
changeset 1833 a4c371728d07
parent 1822 7893174d0fe8
child 1837 7bb70675cd1d
permissions -rwxr-xr-x
scripts: enhance and fix the release script
     1 #!/bin/bash
     2 #set -x
     3 
     4 my_name="$( basename "${0}" )"
     5 
     6 usage() {
     7     cat <<-_EOF_
     8 		Usage:
     9 		    ${my_name} <repos_dir> <M.m.p>
    10 	_EOF_
    11 }
    12 
    13 repos="${1}"
    14 version="${2}"
    15 
    16 [ -n "${repos}"   ] || { usage; exit 1; }
    17 [ -d "${repos}"   ] || { printf "${my_name}: ${repos}: no such file or directory\n"; exit 1; }
    18 [ -n "${version}" ] || { usage; exit 1; }
    19 
    20 gen_bound_revs() {
    21     r1=$( hg log    \
    22           |awk 'BEGIN {
    23                   found=0;
    24                 }
    25                 $1=="'"${label}"':" {
    26                   split($2,a,":"); rev=a[1];
    27                 }
    28                 $0~/^summary:[[:space:]]*[[:digit:]]+\.[[:digit:]]+: '"${msg}"'/ \
    29                 && found==0 {
    30                   printf( "%d\n", rev ); found=1;
    31                 }'
    32         )
    33 
    34     r2=$( hg log -b "${branch}" \
    35           |awk '$1=="changeset:" {
    36                   split($2,a,":");
    37                   printf( "%d\n", a[1] );
    38                   nextfile;
    39                 }'
    40         )
    41 
    42     r1_log=$((r1+log_offset))
    43     if [ ${#r1_log} -gt ${#r2} ]; then
    44         rev_w=${#r1_log}
    45     else
    46         rev_w=${#r2}
    47     fi
    48 }
    49 
    50 print_intro_mail() {
    51     cat <<-_EOF_
    52 		Hello all!
    53 		
    54 		I'm pleased to announce the release of crosstool-NG ${version}!
    55 		
    56 		As usual, there has been quite a number of improvements, new features,
    57 		and bug fixes all around. The most notable changes are listed below:
    58 		
    59 		YEM:
    60 		YEM: PUT YOUR MESSAGE HERE
    61 		YEM:
    62 		
    63 		This marks the beginning of the ${ver_M}.${ver_m} maintenance branch, and the end of
    64 		the previous maintenance branch. As always, comments and suggestions
    65 		are most welcome!
    66 		
    67 		The release can be found at the following URLs:
    68 		Changelog: http://ymorin.is-a-geek.org/download/crosstool-ng/crosstool-ng-${version}.changelog
    69 		Tarball:   http://ymorin.is-a-geek.org/download/crosstool-ng/crosstool-ng-${version}.tar.bz2
    70 		Patches:   http://ymorin.is-a-geek.org/download/crosstool-ng/01-fixes/${version}/
    71 		
    72 		As a reminder, the home for crosstool-NG is:
    73 		http://ymorin.is-a-geek.org/projects/crosstool
    74 		
    75 		Crosstool-NG also has a Freshmeat page:
    76 		http://freshmeat.net/projects/crosstool-ng
    77 	_EOF_
    78 }
    79 
    80 print_intro_changelog_full_release() {
    81     cat <<-_EOF_
    82 		crosstool-NG ${version} -- ${date}
    83 		
    84 		This is a feature-release. Significant changes are:
    85 		
    86 		YEM:
    87 		YEM: PUT YOUR MESSAGE HERE
    88 		YEM:
    89 	_EOF_
    90 }
    91 
    92 print_intro_changelog_bug_fix() {
    93     cat <<-_EOF_
    94 		crosstool-NG ${version} -- ${date}
    95 		
    96 		This is a bug-fix-only release.
    97 	_EOF_
    98 }
    99 
   100 print_author_stats() {
   101     printf "\nMany thanks to the people who contributed to this release:\n\n"
   102     prev_author=""
   103     template='{author|person}\n'
   104     hg log -b "${branch}" -r "${r1_log}:${r2}"                  \
   105            --template "${template}"                             \
   106     |sed -r -e 's/"//g;'                                        \
   107     |awk -F '' '{
   108                   nb[$0]++;
   109                 }
   110                 END {
   111                   for( author in nb ) {
   112                     printf( "   %4d  %s\n", nb[author], author );
   113                   }
   114                 }'                                              \
   115     |sort -rn
   116 }
   117 
   118 print_author_shortlog() {
   119     printf "\nHere is the per-author shortlog:\n"
   120     prev_author=""
   121     template='{author|person}|{rev}|{branches}|{desc|firstline}\n'
   122     hg log -b "${branch}" -r "${r1_log}:${r2}"              \
   123            --template "${template}"                         \
   124     |awk -F '' '{
   125                   n=split( $0,a,"|" );
   126                   printf( "%s", gensub("\"","","g",a[1]) );
   127                   printf( "|%0*d", '${rev_w}', a[2] );
   128                   for(i=3;i<=n;i++) {
   129                     printf( "|%s", a[i] );
   130                   }
   131                   printf( "\n" );
   132                 }'                                          \
   133     |sort                                                   \
   134     |while read line; do
   135         author="$( echo "${line}" |cut -d \| -f 1 )"
   136         rev="$( echo "${line}" |cut -d \| -f 2 )"
   137         br="$( echo "${line}" |cut -d \| -f 3 )"
   138         desc="$( echo "${line}" |cut -d \| -f 4- )"
   139 
   140         case "${br}" in
   141             ${branch})  ;;
   142             [0-9]*.*)    continue;;
   143             *) ;;
   144         esac
   145 
   146         case "${desc}" in
   147             Merge.)                 continue;;
   148             *": close "*" branch"*) continue;;
   149 #           *\(merged\))            continue;;
   150         esac
   151 
   152         author="$( echo "${author}" |sed -r -e 's/"//g;' )"
   153 
   154         if [ ! "${prev_author}" = "${author}" ]; then
   155             printf "\n"
   156             printf "    ${author}:\n"
   157             prev_author="${author}"
   158         fi
   159         rev="$( echo "${rev}" |sed -r -e 's/^0*//;' )"
   160 
   161         printf "%s\n" "${desc}"     \
   162         |fmt -w 65                  \
   163         |(first=1; while read l; do
   164             if [ -n "${first}" ]; then
   165                 printf "        [%*d] %s\n" ${rev_w} ${rev} "${l}"
   166                 first=
   167             else
   168                 printf "         %*.*s  %s\n" ${rev_w} ${rev_w} '' "${l}"
   169             fi
   170         done)
   171     done
   172 }
   173 
   174 print_diffstat() {
   175     printf "\nThe diffstat follows:\n\n"
   176     hg diff -r "${r1}:${r2}" --color=never  \
   177     |diffstat -r 2 -p 1 -w 10               \
   178     |tail -n 1                              \
   179     |sed -r -e 's/^ */    /;'
   180 
   181     hg diff -r "${r1}:${r2}" --color=never  \
   182     |diffstat -f 1 -r 2 -p 1 -w 10          \
   183     |head -n -1                             \
   184     |while read file line; do
   185         if [ ${#file} -gt 57 ]; then
   186             file="$( echo "${file}" |sed -r -e 's/^(.{,24}).*(.{28})$/\1.....\2/;' )"
   187         fi
   188         printf "    %-57s %s\n" "${file}" "${line}"
   189     done
   190 }
   191 
   192 print_short_diffstat() {
   193     printf "\nThe short diffstat follows:\n\n"
   194 
   195     eval total=$(( $(
   196         hg diff -r "${r1}:${r2}" --color=never "${i}"                               \
   197         |diffstat -r 2 -p 1 -w 10                                                   \
   198         |tail -n 1                                                                  \
   199         |sed -r -e 's/^[[:space:]]*[[:digit:]]+ files? changed(,[[:space:]]+|$)//;' \
   200                 -e 's/([[:digit:]]+)[^-\+]+\((-|\+)\)/\1/g;'                        \
   201                 -e 's/,//g; s/ /+/; s/^$/0/;'
   202     ) ))
   203     printf "    %-24.24s %5d(+/-)\n" "Total" ${total}
   204     others=${total}
   205 
   206     { for i in              \
   207         kconfig/            \
   208         patches/            \
   209         config/*/           \
   210         scripts/build/*/    \
   211         samples/            \
   212         ; do
   213         eval val=$(( $(
   214             hg diff -r "${r1}:${r2}" --color=never "${i}"                               \
   215             |diffstat -r 2 -p 1 -w 10                                                   \
   216             |tail -n 1                                                                  \
   217             |sed -r -e 's/^[[:space:]]*[[:digit:]]+ files? changed(,[[:space:]]+|$)//;' \
   218                     -e 's/([[:digit:]]+)[^-\+]+\((-|\+)\)/\1/g;'                        \
   219                     -e 's/,//g; s/ /+/; s/^$/0/;'
   220         ) ))
   221         if [ ${val} -gt $((total/100)) ]; then
   222             printf "%d %s\n" $(((1000*val)/total)) "${i}"
   223             others=$((others-val))
   224         fi
   225     done; printf "%d Others\n" $(((1000*others)/total)); }  \
   226     |sort -nr                                               \
   227     |{ while read v i; do
   228         if [ "${i}" = "Others" ]; then
   229             others=${v}
   230         else
   231             printf "    %-24.24s %3d.%d%%\n" "${i}" $((v/10)) $((v%10))
   232         fi
   233        done; printf "    %-24.24s %3d.%d%%\n" "Others" $((others/10)) $((others%10)); }
   234 }
   235 
   236 ver_M="$( printf "${version}" |cut -d . -f 1 )"
   237 ver_m="$( printf "${version}" |cut -d . -f 2 )"
   238 ver_p="$( printf "${version}" |cut -d . -f 3 )"
   239 
   240 prefix="$(pwd)/crosstool-ng-${version}"
   241 pushd "${repos}" >/dev/null 2>&1
   242 
   243 printf "Checking for existing tag: "
   244 if hg tags |grep -E '^'"crosstool-ng-${version}"'\>' >/dev/null; then
   245     printf "already tagged\n"
   246     exit 1
   247 fi
   248 printf "no\n"
   249 
   250 if [ ${ver_p} -eq 0 ]; then
   251     print_mail="yes"
   252     print_intro_changelog="print_intro_changelog_full_release"
   253     label="parent"
   254     msg="create maintenance branch, (update|bump) version to [[:digit:]]+"'\'".[[:digit:]]+"'\'".0"'$'
   255     branch="default"
   256     log_offset=0
   257 else
   258     print_mail="no"
   259     print_intro_changelog="print_intro_changelog_bug_fix"
   260     label="changeset"
   261     msg="(update|bump) version to ${ver_M}"'\'".${ver_m}"'\'".$((ver_p-1))"'\+hg$'
   262     branch="${ver_M}.${ver_m}"
   263     log_offset=1
   264 fi
   265 
   266 printf "Computing boundary revisions:"
   267 gen_bound_revs
   268 printf " %d:%d\n" ${r1} ${r2}
   269 
   270 printf "Tagging release:"
   271 hg up "${branch}" >/dev/null
   272 if [ ${ver_p} -eq 0 ]; then
   273     printf " update version"
   274     hg branch "${ver_M}.${ver_m}" >/dev/null
   275     echo "${version}" >".version"
   276     hg ci -m "${ver_M}.${ver_m}: create maintenance branch, update version to ${version}"
   277 else
   278     printf " update version"
   279     echo "${version}" >".version"
   280     hg ci -m "${ver_M}.${ver_m}: update version to ${version}"
   281 fi
   282 
   283 printf ", tag"
   284 hg tag -m "Tagging release ${version}" crosstool-ng-${version}
   285 
   286 printf ", update version"
   287 echo "${version}+hg" >".version"
   288 hg ci -m "${ver_M}.${ver_m}: update version to ${version}+hg"
   289 
   290 printf ", date"
   291 date="$( hg log -r crosstool-ng-${version} --template '{date|isodate}\n'    \
   292          |sed -r -e 's/-|://g; s/ /./; s/ //;'                              \
   293        )"
   294 printf ", done.\n"
   295 
   296 if [ ${ver_p} -eq 0 ]; then
   297     printf "Generating release mail:"
   298     printf " intro"
   299     print_intro_mail        > "${prefix}.mail"
   300     printf ", stats"
   301     print_author_stats      >>"${prefix}.mail"
   302     printf ", shortlog"
   303     print_author_shortlog   >>"${prefix}.mail"
   304     printf ", diffstat"
   305     print_short_diffstat    >>"${prefix}.mail"
   306     printf ", done.\n"
   307 fi
   308 
   309 printf "Generating release changelog:"
   310 printf " intro"
   311 ${print_intro_changelog}    > "${prefix}.changelog"
   312 printf ", stats"
   313 print_author_stats          >>"${prefix}.changelog"
   314 printf ", shortlog"
   315 print_author_shortlog       >>"${prefix}.changelog"
   316 printf ", diffstat"
   317 print_diffstat              >>"${prefix}.changelog"
   318 printf ", done.\n"
   319 
   320 popd >/dev/null 2>&1
   321 
   322 printf "Creating tarball:"
   323 prefix="crosstool-ng-${version}"
   324 printf " cloning"
   325 hg clone "${repos}" "${prefix}" >/dev/null
   326 hg up -R "${prefix}" "${prefix}" >/dev/null
   327 date="$( hg log -R "${prefix}" -r "${prefix}" --template '{date|rfc822date}\n' )"
   328 printf ", purging"
   329 rm -rf "${prefix}/"{.hg,.hgtags,.hgignore}
   330 printf ", tarball"
   331 tar cjf "${prefix}.tar.bz2" "${prefix}"
   332 printf ", sum"
   333 for s in md5 sha1 sha512; do
   334     ${s}sum "${prefix}.tar.bz2" >"${prefix}.tar.bz2.${s}"
   335 done
   336 printf ", cleaning"
   337 rm -rf "${prefix}"
   338 printf ", touch"
   339 touch -d "${date}" "${prefix}"*
   340 printf ", done.\n"
   341 
   342 if [ ${ver_p} -eq 0 ]; then
   343     printf "\nAn editor will be launched for you to edit the mail.\n"
   344     read -p "Press enter when ready..." foo
   345     cp "${prefix}.mail"{,.orig}
   346     vi "${prefix}.mail"
   347     diff -du -U 1 "${prefix}.mail"{.orig,} |patch -p0 "${prefix}.changelog" >/dev/null
   348     rm -f "${prefix}".{mail,changelog}.orig
   349 fi
   350 
   351 printf "\nAn editor will be launched for you to review the changelog.\n"
   352 read -p "Press enter when ready..." foo
   353 vi "${prefix}.changelog"
   354 
   355 printf "\nNow, you can push the changes with:   hg push -R '${repos}'\n"