#!/bin/bash # Style NC='\e[0m' red='\e[0;31m' blue='\e[1;34m' green='\e[0;32m' bold='\e[1m' lines=`perl -E 'say "-" x 80'` EDITOR="${EDITOR:-vim}" # ============================================================================== # Usage and Help # ============================================================================== usage() { # Format this section with 75 columns. cat << EOF ${release_script} [-amend FILE] [-branch BRANCH] [-date DATE] [-r [SPIN]] [-R [SPIN]] [-S [SPIN]] EOF return 0 } extended_usage() { echo -e "${bold}Usage:${NC}" usage; print_info "Run \"${release_script} -help\" for detailed usage information." } help() { # Format this section of text with 75 columns. #cat << EOF echo -e "\ ${bold}NAME${NC} ${release_script} - The Linaro GCC snapshot, and release script. ${bold}SYNOPSIS${NC}" usage echo -e "\ ${bold}DESCRIPTION${NC}" echo -e "\ \"${release_script}\" is a utility that is used to create tarballs and branches for Linaro toolchain GCC monthly snapshots, quarterly releases. By default ${release_script} creates a snapshot tarball, branch, and tag. ${bold}PRECONDITIONS${NC} ${release_script} needs to be executed in the top-level GCC source directory. The GCC source directory must be a git repository. This script will not work on a GCC source tarball or a GCC SVN repository. The GCC source git repository must have the branch that the release or snapshot will based on currently checked out. ${bold}OPTIONS${NC}" cat << EOF -amend FILE FILE is the path to the optional amend file to pass to gitlog-to-changelog. For more information on how to use this feature please run gitlog-to-changelog --help. -branch BRANCH Derive (track) the snapshot or release from branch BRANCH. The default is to use the existing branch. -date DATE Create DATE snapshot or release. The DATE may be in the following formats: YYYY.MM, YYYY-MM, YYYY/MM, YYYY.MM.DD, YYYY-MM-DD, YYYY/MM/DD. The Default is the current date. -help Print this extended help text. -R [SPIN] This tells ${release_script} to create a release tarball, branch and tag with an optional spin number SPIN. By default no SPIN number is used. SPIN must be > 0 if specified. -S [SPIN] [Default] This explicitly tells ${release_script} to create a snapshot tarball, branch, and tag with an optional spin number SPIN. By default no SPIN number is used. SPIN must be > 0 if specified. -r [SPIN] This tells ${release_script} to create a release candidate tarball, branch and tag with an optional spin number SPIN. By default SPIN number '1' is used. SPIN must be >= 1. This option will append -rcSPIN on the end of the release string. -usage EOF echo -e "\ Print the short form usage text. See '${bold}SYNOPSIS${NC}' above. ${bold}EXAMPLES${NC} ${bold}Snapshot Examples: ${bold}Implicit Snapshot Based on Current Branch:${NC} ${release_script} ${bold}Explicit Snapshot Based on Current Branch With Today's Date:${NC} ${release_script} -S ${bold}Snapshot Based on Current Branch With Commit Message Fixup With Today's Date:${NC} ${release_script} -S \\ -a /tcwg-release-tools/gitlog-amend-gcc-5 ${bold}Snapshot Based on Linaro GCC 5 Branch With Today's Date:${NC} ${release_script} -S -b remotes/origin/linaro/gcc-5-branch ${bold}Respin Snapshot Based On A Snapshot Branch And An Explicit Date:${NC} ${release_script} -S 1 -d 2015.06 \\ -b remotes/origin/linaro-local/snapshots/linaro-5.1-2015.06 ${bold}Release Candidate Examples: ${bold}Release Candidate With Implicit Spin Number Based On A Snapshot Branch And An Explicit Date:${NC} ${release_script} -d 2015.06 \\ -b remotes/origin/linaro-local/snapshots/linaro-5.1-2015.06 ${bold}Release Candidate Based On A Snapshot Branch And An Explicit Date:${NC} ${release_script} -r 1 -d 2015.06 \\ -b remotes/origin/linaro-local/snapshots/linaro-5.1-2015.06 ${bold}Release Candidate Respin Based On The Release Branch With An Explicit Date:${NC} ${release_script} -r 2 -d 2015.06 \\ -b remotes/origin/linaro-local/releases/linaro-5.1-2015.06 ${bold}Release Examples: ${bold}Release Based on Current Branch With Today's Date:${NC} ${release_script} -R ${bold}Release Based on Release Branch With An Explicit Date:${NC} ${release_script} -R -d 2015.05 \\ -b remotes/origin/linaro-local/releases/linaro-5.1-2015.06 ${bold}Release Respin Based on Release Branch With An Explicit Date:${NC} ${release_script} -R 1 -d 2015.05 \\ -b remotes/origin/linaro-local/releases/linaro-5.1-2015.06 ${bold}AUTHORS${NC} ${release_script} was written by: Yvan Roux Christophe Lyon Ryan S Arnold " return 0 } # ============================================================================== # Functions # ============================================================================== print_step() { echo -e "${blue}${lines}\n${red}** ${1}\n${blue}${lines}${NC}\n" } print_info() { echo -e "${blue}** ${NC}${1}${NC}" } clean() { ask "${bold}May I remove ${REL_DIR}/git [N/y] ?${NC}" user_ok if [ "$user_ok" = "y" ]; then if [ -d "$REL_DIR/git" ]; then rm -rf $REL_DIR/git if [ $? -eq 0 ]; then print_info "Removed ${REL_DIR}/git" fi fi fi git_out="" # check to see if the local_branch has been created. git rev-parse --verify ${local_branch} &>/dev/null if [ $? -eq 0 ]; then ask "${bold}May I remove the local branch named \"${local_branch}\" as part of the cleanup process [N/y] ?${NC}" user_ok if [ "$user_ok" = "y" ]; then git_out=$(git branch -D ${local_branch}) print_info "${git_out}" fi fi # If there is a tag created/associated with this release then it should be # removed as well. if [ x"`git tag -l ${release_tag}`" != x ]; then ask "${bold}May I remove the local tag named \"${release_tag}\" as part of the cleanup process [N/y] ?${NC}" user_ok if [ "$user_ok" = "y" ]; then git_out=$(git tag -d ${release_tag}) print_info "${git_out}" fi fi } clean_and_die() { echo -e "${red}${bold}ERROR: ${NC}${bold}${1}${NC}" clean exit 1 } die() { echo -e "${red}${bold}ERROR: ${NC}${bold}${1}${NC}" exit 1 } # arg1 : a sentence # arg2 : a variable # print arg1 and gather user input in arg2 ask() { echo -n -e "${blue}** ${NC}${1} ${NC}" eval "read ${2}" } changelog() { echo $release > $REL_DIR/git/gcc/LINARO-VERSION for cl in $(find $REL_DIR/git -name 'ChangeLog.linaro'); do if [ x"$cl" = x"$REL_DIR/git/gcc/ChangeLog.linaro" ]; then cat - $cl > $cl.new < $chglmsg * LINARO-VERSION: Update. EOF else cat - $cl > $cl.new < $chglmsg EOF fi mv $cl.new $cl done pushd $REL_DIR/git 1>/dev/null git commit -a -m "${commitmsg}" popd 1>/dev/null } export_source() { pushd $REL_DIR/git 1>/dev/null git checkout-index -f -a --prefix=$REL_DIR/gcc-linaro-${rname}/ popd 1>/dev/null } build() { pushd $REL_DIR/gcc-linaro-${rname} 1>/dev/null env SOURCEDIR=`pwd`/gcc/doc DESTDIR=`pwd`/INSTALL ./gcc/doc/install.texi2html env MAKE="make -j4" contrib/gcc_build -d $REL_DIR/gcc-linaro-${rname} \ -o $REL_DIR/objdir -c \ "--enable-generated-files-in-srcdir --disable-multilib" build mv -v $REL_DIR/objdir/gcc/po/*.gmo $REL_DIR/gcc-linaro-${rname}/gcc/po/ popd 1>/dev/null } md5() { pushd $REL_DIR/gcc-linaro-${rname} 1>/dev/null cat - >MD5SUMS <>MD5SUMS popd 1>/dev/null } tag() { git tag -a ${release_tag} -m "${tagmsg}" if [ $? != 0 ]; then clean_and_die "Creation of git tag ${release_tag} failed." fi # Query the git repo for the tag as a sanity step. print_info "${bold}Created tag \"${red}`git tag -l ${release_tag}`${NC}${bold}\" with tag message \"${red}${tagmsg}${NC}${bold}\"" ask "${bold}Does this look right [N/y] ?${NC}" user_ok if [ "$user_ok" != "y" ]; then clean exit 1 fi } # ============================================================================== # Settings # ============================================================================== GIT_REPO=`pwd` #/work/sources/gcc-linaro/gcc # Leave these unset by default! SPIN= RELEASE= SNAPSHOT= RC= NAME=`git config user.name` EMAIL=`git config user.email` date=$(date +%Y-%m-%d) gitlog_amend= release_script="`basename $0`" # Arguments. The first colon puts getopts into silent error reporting mode # which sets $OPTARG to the unknown option if one is encountered. while getopts ":a:b:d:hrRSu" options do case $options in a ) gitlog_amend="--amend $OPTARG" ;; b ) tracked_branch="$OPTARG" ;; d ) DATE="$OPTARG" ;; h ) help; exit 1; ;; r ) RC=1 # If the next input is not a -option then it is an optional SPIN # arg. [[ ${!OPTIND} =~ ^-. ]] || { SPIN=${!OPTIND} ; OPTIND=$(( $OPTIND + 1)); } # The default SPIN for release candidates is '1'. Set it if it's # undefined or the null string. The leading colon causes the # variable expansion to take place without evaluating the expansion # as a statement. : ${SPIN:=1} ;; R ) RELEASE=1 # If the next input is not a -option then it is an optional SPIN # arg. [[ ${!OPTIND} =~ ^-. ]] || { SPIN=${!OPTIND} ; OPTIND=$(( $OPTIND + 1)); } ;; S ) SNAPSHOT=1 # If the next input is not a -option then it is an optional SPIN # arg. [[ ${!OPTIND} =~ ^-. ]] || { SPIN=${!OPTIND} ; OPTIND=$(( $OPTIND + 1)); } ;; u ) extended_usage; exit 1; ;; \?) print_info "Option -${BOLD}$OPTARG${NC} Unsupported." ;; : ) extended_usage; die "Option \"-$OPTARG\" requires an argument." ;; esac done if [ $# -lt 1 ]; then extended_usage fi shift $(($OPTIND - 1)) if [ "x$DATE" = "x" ]; then DATE=$(date +%Y.%m) else #`date` won't accept dates with '.' in them but the user will very likely # try to use them. We just support it for convenience. DATE=${DATE//./-} if [ ${#DATE} -lt 8 ]; then DATE="${DATE}-01" fi # Pass the user's input DATE through `date` for validation. DATE=$(date -d "$DATE" +%Y.%m 2>&1) if [ $? -eq 1 ]; then # $DATE will contain the error message from `date`. die "$DATE" fi fi if [[ "${RELEASE:+rel}" = "rel" && "${SNAPSHOT:+snap}" = "snap" ]]; then die "-R and -S can not be specified at the same time." elif [[ "${RELEASE:+rel}" = "rel" && "${RC:+rc}" = "rc" ]]; then die "-R and -r can not be specified at the same time." elif [[ "${RC:+rc}" = "rc" && "${SNAPSHOT:+snap}" = "snap" ]]; then die "-r and -S can not be specified at the same time." fi if [[ "${RELEASE:+rel}" != "rel" && "${SNAPSHOT:+snap}" != "snap" && "${RC:+rc}" != "rc" ]]; then print_info "${bold}${release_script} will default to creating a snapshot.${NC}" SNAPSHOT=1 fi # This uses variable substitution to test if SPIN is set, and NOT the empty # string which protects against -S "" or -R "" (which sets SPIN to the empty # string). if [ "${SPIN:+set}" = "set" ]; then # Test if the user input contains anything other than numbers. if [[ ${SPIN} =~ [^0-9] ]]; then die "${RELEASE:+Release}${Snapshot:+Snapshot}${RC:+Release candidate} with SPIN input \"${SPIN}\" is not a number." elif [[ ${SPIN} -le 0 ]]; then die "${RELEASE:+Release}${Snapshot:+Snapshot}${RC:+Release candidate} with SPIN number '${SPIN}' must be greater than zero." fi fi # Test if the current working directory is a git directory. if [ x"`git rev-parse --is-inside-work-tree 2>/dev/null`" != xtrue ]; then die "${GIT_REPO} is not a git repository." elif [ ! -d "${GIT_REPO}/gcc" ]; then die "${GIT_REPO} is not the top-level GCC source directory." fi if [ "x${tracked_branch}" = "x" ]; then # If the user didn't specify a tracking branch, just use the current branch tracked_branch="`git rev-parse --abbrev-ref HEAD`" fi vstring=$(git show "$tracked_branch":gcc/BASE-VER) release=${vstring%.*}-"$DATE" # The local branch can have the SPIN number on the name. local_branch=${SNAPSHOT:+snapshots/}${RELEASE:+releases/}linaro-${release}${SPIN:+-${RC:+rc}$SPIN} # The local branch will be pushed to the remote branch for the snapshot/release # and therefore the remote branch shouldn't use the spin on the name. # Release candidates should be pushed to a remote release branch (sans rcX). # NOTE: This is for reference only and not to be used unless you know the # real remote name. remote_branch=\[remote\]/linaro-local/${SNAPSHOT:+snapshots}${RELEASE:+releases}${RC:+releases}/linaro-${release} # The rest of the uses of ${release} should include the SPIN number so add the # SPIN number if it was specified. release="${release}${SPIN:+-${RC:+rc}${SPIN}}" # Differentiate between Snapshots and Releases, depending on what's set. rname=${SNAPSHOT:+snapshot-}$release chglmsg="GCC Linaro ${release} ${SNAPSHOT:+snapshot}${RELEASE:+release}${RC:+release candidate}." commitmsg="Make Linaro GCC ${SNAPSHOT:+Snapshot }${RELEASE:+Release }${RC:+Release Candidate }${release}." # Replace 'Make' with 'Tag' for the tag message. tagmsg=${commitmsg/Make/Tag} release_tag="linaro-${rname}" REL_DIR=`pwd`/../release/gcc-linaro-${rname} # ============================================================================== # Prepare Sources # ============================================================================== print_info "${bold}You are about to create ${RELEASE:+release }${RC:+release candidate }${red}${rname}" print_info "${bold}from a new local branch named \"${red}${local_branch}${NC}${bold}\"" if [ x"${local_branch}" = x"`git rev-parse --abbrev-ref HEAD`" ]; then die "Local branch \"${local_branch}\" already exists and your tree is checked out in it." fi print_info "${bold}The ${RELEASE:+release}${SNAPSHOT:+snapshot}${RC:+release candidate} will be tagged \"${red}${release_tag}${NC}${bold}\"" print_info "${bold}The local branch should be pushed to ${red}${remote_branch}" print_info "${bold}This local branch will track ${red}${tracked_branch}" # Terminal lines (minus 7 to account for interesting prior output. terminal_lines=$(($(tput lines) - 7)) ask "${bold}To see the most recent commits on the tracked branch press [Enter]" user_ok # the last ten commits should be more than enough. git log -n 10 ${tracked_branch} 2>/dev/null| head -n ${terminal_lines} ask "${bold}Does this look OK [N/y] ?" user_ok if [ "$user_ok" != "y" ]; then # No need to clean here since we haven't actually done anything. exit 1 fi print_info "${bold}Creating git work dir ${REL_DIR}/git" git-new-workdir $GIT_REPO $REL_DIR/git || die "Couldn't extract sources." print_info "${bold}Checking out branch ${local_branch}" pushd $REL_DIR/git 1>/dev/null git checkout -B ${local_branch} ${tracked_branch} 2>/dev/null popd 1>/dev/null print_info "${bold}Creating ${SNAPSHOT:+snapshot}${RELEASE:+release}${RC:+release candidate} ChangeLog entries.${NC}" changelog print_info "${bold}The following commit was made when updating the ChangeLog entries.${NC}" # Display the changes from the ChangeLog commit. git log -n 1 ${local_branch} 2>/dev/null # Empty line seems appropriate for visual continuity. echo "" ask "${bold}Does this look OK [N/y] ?" user_ok if [ "$user_ok" != "y" ]; then clean exit 1 fi tag export_source # Generate ChangeLog.linaro from git commit messages for GCC branches >= 5 if [ ${vstring%%.*} -ge "5" ]; then SINCE=$(git log --format=%ai --grep="git-svn-id" | head -n 1) mydir="$(cd $(dirname $0); pwd)" ${mydir}/gitlog-to-changelog --since ${SINCE%% *} --no-cluster \ --strip-change-id --format=%B --strip-tab \ ${gitlog_amend} > $REL_DIR/gcc-linaro-${rname}/ChangeLog.linaro # Some git commit messages are not formatted correctly. Fix them manually. ask "${bold}Please check the generated ChangeLog and update it if needed." user_ok $EDITOR $REL_DIR/gcc-linaro-${rname}/ChangeLog.linaro fi build md5 pushd $REL_DIR 1>/dev/null tar cfJ gcc-linaro-${rname}.tar.xz gcc-linaro-${rname} popd 1>/dev/null # Come back to initial state, in particular forget about # ChangeLog.linaro and gcc/LINARO-VERSION git reset --hard