diff options
-rwxr-xr-x | tcwg-release-tag.sh | 741 | ||||
-rwxr-xr-x | tcwg-release-tarball.sh | 159 |
2 files changed, 900 insertions, 0 deletions
diff --git a/tcwg-release-tag.sh b/tcwg-release-tag.sh new file mode 100755 index 0000000..b9e9d9d --- /dev/null +++ b/tcwg-release-tag.sh @@ -0,0 +1,741 @@ +#!/bin/bash + +# Style +#NC='\e[0m' +#red='\e[0;31m' +#blue='\e[1;34m' +#green='\e[0;32m' +#bold='\e[1m' +#italic='\e[3m' +# ============================================================================== +# Usage and Help +# ============================================================================== +usage() { + # Format this section with 75 columns. + cat << EOF + ${release_script} [-d DATE] [-h] [-e REMOTE] [-r [RC] [SPIN]] [-R [SPIN]] + [-S [SPIN]] [-t TRACK] [-u] [-v] +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}REMOTES${NC} + ${release_script} attempts to be intelligent (and slightly permissive) + about handling git remote naming. Its ability to do so is complicated + by how the Linaro git mirror is set-up. + + Linaro maintains a mirror of the upstream FSF git repository in order + to locally stage backports, store snapshot and release branches, and store + snapshot, release candidate, and release tags. + + The Linaro GCC mirror includes a writeable ${bold}linaro-local/${NC} namespace + that is not present on the upstream FSF git repository. + + The following, Linaro only, writable namespaces are used for storing + Linaro snapshot and release branches, respectively: + + ${bold}linaro-local/snapshots/${NC} + ${bold}linaro-local/releases/${NC} + + Linaro provides read-only access to the Linaro GCC mirror via ${italic}gitolite${NC} + and read-write access (only to the linaro-local/* namespace) via ${italic}gerrit${NC}. + + Here is the recommended setup of the gcc git repository: + + 1) Clone the read-only gitolite repository as 'origin': + + git clone https://git.linaro.org/toolchain/gcc.git gcc.git + + ${italic}${bold}Note: ${NC}${italic} If you would like use a remote name other than 'origin' run + the following command and then replace 'origin' in the examples with + your desired remote name.${NC} + + git remote rename origin ${italic}<remote>${NC} + + 2) Set the pushurl for the default remote as the gerrit server: + + git config remote.origin.pushurl \\ + ssh://review.linaro.org:29418/toolchain/gcc + + 3) Set the gerrit username: + + ${italic}${bold}Note: ${NC}${italic}To find your gerrit username look on: review.linaro.org + -> [User Name] -> Settings -> username + + git config remote.origin.username ${italic}<Linaro gerrit username>${NC} + + This is an example of what .git/config will look like for remote + 'origin' after setting up the repository: + + [remote "origin"] + url = https://git.linaro.org/toolchain/gcc.git + fetch = +refs/heads/*:refs/remotes/origin/* + pushurl = ssh://review.linaro.org:29418/toolchain/gcc + username = ryanarn + +${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. + + See the following subsection on ${bold}REMOTES${NC} for a + recommendation on how how to clone the GCC repository in a manner which + will allow pushing changes to the repository. + +${bold}OPTIONS${NC}" + cat << EOF + -d 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. + + -e REMOTE + This specifies the remote (as REMOTE) to use when + outputting the push instructions. NOTE: This script does + not actually push to the remotes. + + It is necessary to designate an alternate FSF remote in + order to push tags and gcc/LINARO-VERSION updates to the + upstream branches for snapshots. + + -h + 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 [RC] [SPIN] + This tells ${release_script} to create a release candidate + tarball, branch and tag with an optional release candidate + number RC and an optional spin number SPIN. By default RC + number '1' is used and SPIN is left blank/off. RC must be + >= 1. SPIN must be >= 1 if used. This option will append + "[-SPIN]-rcRC" on the end of the release string. + + Note: If you want to specify a SPIN you MUST specify an RC + argument as well or ${release_script} will make the first + argument the RC value. + + -t TRACK_REF + Derive (track) the snapshot, release, or release candidate + from tacked reference TRACK_REF. The default is to use the + existing branch and not use a tag. + + -v + Emit verbose output. Use more than once to increase output + further. + + -u +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 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 <yvan.roux@linaro.org> + Christophe Lyon <christophe.lyon@linaro.org> + Ryan S Arnold <ryan.arnold@linaro.org> +" + return 0 +} + +# ============================================================================== +# Functions +# ============================================================================== +print_info() { + echo -e "${blue}** ${NC}${1}${NC}" +} + +clean() { + # This will bring us back to the starting directory even if we're already + # there. + popd &>/dev/null + + # Return the tree to the starting branch if it's not already there. We + # can't be in one of the working branches if we want to delete it. + if [ "${save_branch:+set}" = "set" ]; then + print_info "${bold}Returning tree to the saved branch..." + git checkout ${save_branch} 2>&1>/dev/null + 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 + git_out=$(git branch -D ${local_branch}) + print_info "${git_out}" + fi + + if [[ "${SNAPSHOT:+set}" = "set" && "${SPIN:+set}" != "set" ]]; then + # check to see if the local_int_branch has been created. + git rev-parse --verify ${local_int_branch} &>/dev/null + if [ $? -eq 0 ]; then + git_out=$(git branch -D ${local_int_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 + git_out=$(git tag -d ${release_tag}) + print_info "${git_out}" + 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 +} + +handle_ctrl_c() { + # set -x is not well handled by trap and cleanup, so turning it off. + (( VERBOSITY >= 2 )) && set +x + clean_and_die "User hit ctrl-c. Operation aborted." +} + +debug_handler() { + echo "$BASH_COMMAND" | grep -v "echo\|print\|exec\|eval\|\[\|\]" +} + +# arg1: a date in any format +# print a sanitized version of the date, or the error +# as generated by `date` if the input is invalid. The +# return value is non-zero if there's an error. +sanitize_input_date() { + local in_date="$1" + in_date=${in_date//./-} + + # If the in_date doesn't include the 'day' add it on + # because `date` expects it. + [[ ${#in_date} -lt 8 ]] && { in_date="${in_date}-01"; } + + local sanitized_date= + sanitized_date="$(date -d ${in_date} +%Y-%m-%d 2>&1)" + ret=$? + echo "${sanitized_date}" + + return $ret; +} + +# Return true if $1 is a valid tag reference. +is_tag() { + $(git rev-parse -q --verify $1^{tag} &>/dev/null) + return $? + +} + +changelog() { + echo "${SNAPSHOT:+Snapshot }${release}" > $REL_DIR/gcc/LINARO-VERSION + for cl in $(find $REL_DIR -name 'ChangeLog.linaro'); do + if [ x"$cl" = x"$REL_DIR/gcc/ChangeLog.linaro" ]; then + cat - $cl > $cl.new <<EOF +$today $NAME <$EMAIL> + + $chglmsg + * LINARO-VERSION: Update. + +EOF + else + cat - $cl > $cl.new <<EOF +$today $NAME <$EMAIL> + + $chglmsg + +EOF + fi + mv $cl.new $cl + done + + if [ ${vstring%%.*} -ge "5" ]; then + git commit -a -F- <<EOF +${commitmsg} + + gcc/ + * LINARO-VERSION: Update. +EOF + else + git commit -a -m "${commitmsg}" + fi +} + +bump_and_dev() { + local bump_to="$1" + echo "${bump_to}" > $REL_DIR/gcc/LINARO-VERSION + git commit -q -a -F- <<EOF + gcc/ + * LINARO-VERSION: Bump version number, post ${SNAPSHOT:+snapshot}${RELEASE:+release}${CANDIDATE:+release candidate}. +EOF + print_info "${bold}Bumped gcc/LINARO-VERSION to ${bump_to} in $(git rev-parse --abbrev-ref HEAD)" +} + +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}\"" +} + +info() { + print_info "${bold}${italic}You are about to create ${SNAPSHOT:+snapshot }${RELEASE:+release }${CANDIDATE:+release candidate }${red}${rname}:" + print_info "${bold}+--------------------------------------------------------------------------------" + print_info "${bold}+ Tracking remote reference:" + print_info "${bold}| ${red}${track}" + print_info "${bold}+ With new local branch:" + print_info "${bold}| ${red}${local_branch}" + print_info "${bold}+ The ${RELEASE:+release}${SNAPSHOT:+snapshot}${CANDIDATE:+release candidate} will be tagged as:" + print_info "${bold}| ${red}${release_tag}" + print_info "${bold}+ The local branch has gcc/LINARO-VERSION set to:" + print_info "${bold}| ${red}$(git show ${track}:gcc/LINARO-VERSION)" + print_info "${bold}+ For the ${SNAPSHOT:+snapshot}${RELEASE:+release}${CANDIDATE:+release candidate} gcc/LINARO-VERSION will be set:" + print_info "${bold}| ${red}${SNAPSHOT:+Snapshot }${release}" + print_info "${bold}+ The gcc/LINARO-VERSION will be bumped to:" + print_info "${bold}| ${red}${bump_mode_to}" + print_info "${bold}+ The local branch should be pushed to:" + print_info "${bold}| ${red}${remote_mode_branch}" + if [[ "${SNAPSHOT:+set}" = "set" && "${SPIN:+set}" != "set" ]]; then + print_info "${bold}| +-----------------------------------------------------------------------------" + print_info "${bold}| + The local integration branch is:" + print_info "${bold}| | ${red}${local_int_branch}" + print_info "${bold}| + The local integration branch will have gcc/LINARO-VERSION bumped:" + print_info "${bold}| | ${italic}from: ${red}$(git show ${remote_int_branch}:gcc/LINARO-VERSION)" + print_info "${bold}| | ${italic}to: ${red}${bump_int_to}" + print_info "${bold}| + The local integration branch should be pushed to:" + print_info "${bold}| | ${red}${remote_int_branch}" + print_info "${bold}+--+-----------------------------------------------------------------------------" + else + print_info "${bold}+--------------------------------------------------------------------------------" + fi + print_info "${italic}${bold}After the build completes push branches and tags to the Linaro git repo:" +} + +# ============================================================================== +# Settings +# ============================================================================== + +# Clear the directory stack so a popd in clean() always returns us to the right +# place. +dirs -c + +GIT_REPO="$PWD" +VERBOSITY=0 + +# Leave these unset by default! +SPIN= +RELEASE= +SNAPSHOT= +RC= +CANDIDATE= +REMOTE= + +NAME="$(git config user.name)" +EMAIL="$(git config user.email)" +today="$(date +%Y-%m-%d)" + +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 ":b:d:e:hnrRSt:uv" options +do + case $options in + d ) DATE=$(sanitize_input_date "$OPTARG") + #if [ $? -ne 0 ]; then + # ${DATE} will contain the error message + #die "${DATE}" + #fi + # We only use YYYY.MM format + DATE=$(date -d "$DATE" +%Y.%m 2>&1) + ;; + e ) REMOTE="$OPTARG" + ;; + h ) help; exit 1; + ;; + r ) CANDIDATE=1 + # If the next input is not a -option then it is an optional RC arg. + [[ ${!OPTIND} =~ ^-. ]] || { RC=${!OPTIND} ; OPTIND=$(( OPTIND + 1 )); } + + # If the next input is not a -option then it is an optional SPIN + # arg. + [[ ${!OPTIND} =~ ^-. ]] || { SPIN=${!OPTIND} ; OPTIND=$(( OPTIND + 1 )); } + + # The default RC 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. + : ${RC:=1} + # SPIN is left unset if not provided by the user. + ;; + 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 )); } + ;; + t ) TRACK_REF="$OPTARG" + ;; + u ) extended_usage; exit 1; + ;; + v ) (( VERBOSITY=VERBOSITY+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 DATE wasn't set by the user, set it. +: ${DATE:=$(date -d "$today" +%Y.%m)} + +if [[ "${RELEASE:+rel}" = "rel" && "${SNAPSHOT:+snap}" = "snap" ]]; then + die "-R and -S can not be specified at the same time." +elif [[ "${RELEASE:+rel}" = "rel" && "${CANDIDATE:+rc}" = "rc" ]]; then + die "-R and -r can not be specified at the same time." +elif [[ "${CANDIDATE:+rc}" = "rc" && "${SNAPSHOT:+snap}" = "snap" ]]; then + die "-r and -S can not be specified at the same time." +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}${CANDIDATE:+Release candidate} with SPIN input \"${SPIN}\" is not a number." + elif [[ ${SPIN} -le 0 ]]; then + die "${RELEASE:+Release}${Snapshot:+Snapshot}${CANDIDATE:+Release candidate} with SPIN number '${SPIN}' must be greater than zero." + fi +fi + +if [ "${RC:+set}" = "set" ]; then + # Test if the user input contains anything other than numbers. + if [[ ${RC} =~ [^0-9] ]]; then + die "Release candidate with RC input \"${RC}\" is not a number." + elif [[ ${RC} -lt 1 ]]; then + die "Release candidate with RC number '${RC}' must be greater than one." + 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 + +# Handle verbosity mode +if (( VERBOSITY == 1 )); then + trap "debug_handler" DEBUG; +elif (( VERBOSITY == 2 )); then + exec 4> >( grep -v "^++\|echo\|print\|exec\|eval\|\[\|\]" >&2) + BASH_XTRACEFD=4 + set -x; +elif (( VERBOSITY >= 3 )); then + set -x; +fi + +# If the REMOTE hasn't been specified, default to 'origin'. +: ${REMOTE:=origin} + +# Release-Candidates and Releases are both pushed to the release branch +# since there is a strict linear progression from candidates to releases. +# +# If the user is tracking a release tag or candidate tag to build a new +# candidate or release, we need to checkout from the release branch and not the +# tag so that we don't get merge conflicts with a previous rc 'bump' when the +# new series is pushed, or miss a cherry-picked patch on the release branch. +# The following is a merge-conflict due to checking out linaro-6.1-2018.08-rc2 +# from the linaro-6.1-2016.08-rc1 tag: +# +# linaro-local/releases/linaro-6.1-2016.08 +# o - Backport Commit +# o - FSF Branch Merge Commit +# o - Snapshot Version Commit +# o - -rc1 Version Commit <--- [TAG] linaro-6.1-2016.08-rc1 +# o - -rc2~dev Version Bump Commit | +# o - Cherry-Picked Patch Commit +-- releases/linaro-6.1-2016.08-rc2 +# o - Backport Commit +# ^ o - FSF Branch Merge Commit +# | o - Snapshot Version Commit +# | o - -rc1 Version Commit +# | linaro-6.1-2016.08-rc2 [TAG] ---> o - -rc2 Version Commit +# | +# +- merge conflict & merge commit <--- git push +# +# Pushing release/linaro-6.1-2016.08-rc2 onto the remote +# linaro-local/releases/linaro-6.1-2016.08 release branch will cause a merge +# conflict between the "-rc2 Version Commit", "-rc2~dev Version Bump Commit", +# and the "Cherry-Picked Patch Commit". While a merge commit could be pushed +# to the linaro-local/releases/linaro-6.1-2016.08 remote branch, the newly +# created linaro-6.1-2016.08-rc2 tag would not represent an accurate view of the +# remote branch head. +# +# The correct behavior is use the tag to determine the correct release branch +# and checkout a working branch (releases/linaro-6.2-2016.08-rc2) from that and +# not the tag. +if [ "${CANDIDATE:+set}" = "set" ] || [ "${RELEASE:+set}" = "set" ]; then + # We only redirect track to a branch if the tag being tracked is not + # a snapshot tag. + if [[ $(is_tag $TRACK_REF) -lt 1 ]] && [[ $(echo $TRACK_REF | grep -c "snapshot") -lt 1 ]]; then + + # The git -r switch denotes that we only want remote branches that a tag + # lives on. We then have to grep for '${REMOTE}' because users might + # have more than one remote (e.g., an additional 'gerrit' remote) or have + # a remote named something other than 'origin'. The tag might show up on + # more than one branch so we restrict to the first branch we find. + BRANCH="`git branch -r --contains ${TRACK_REF} | grep -m 1 ${REMOTE}`" + + # If a branch isn't pushed upstream from a previous invocation, a tag + # might not exist on a remote branch. This should produce an error + # rather than defaulting to 'master'. + if [ "${BRANCH:+set}" != "set" ]; then + clean_and_die "Tag '${TRACK_REF}' not found in any remote branch. Did you push the release branch from your previous build?" + fi + # Remove leading whitespace + BRANCH="${BRANCH#"${BRANCH%%[![:space:]]*}"}" + unset TRACK_REF + fi +fi + +# Track either the BRANCH or the TAG +track="${BRANCH:+${BRANCH}}${TRACK_REF:+${TRACK_REF}}" + +if [ "x${track}" = "x" ]; then + # If the user didn't specify a tracking branch, just use the current + # branch. + track="$(git rev-parse --abbrev-ref HEAD)" +fi + +# Keep track of the branch we start from because we'll want to return there at +# the end or if we have to cleanup prematurely. +save_branch="$(git rev-parse --abbrev-ref HEAD)" + +# Test to make sure the branch or tag exists +git rev-parse --abbrev-ref $track &>/dev/null || die "Reference \"$track\" doesn't exist." + +if [[ x"$(git remote -v | grep "${REMOTE}")" = x ]]; then + die "remote ${REMOTE} is not in your git repository." +fi + +# Place this here so that all info output is after all die conditions. +if [[ "${RELEASE:+rel}" != "rel" && "${SNAPSHOT:+snap}" != "snap" && "${CANDIDATE:+rc}" != "rc" ]]; then + print_info "${bold}${release_script} will default to creating a snapshot." + SNAPSHOT=1 +fi + +vstring=$(git show "$track":gcc/BASE-VER) +release=${vstring%.*}-"$DATE" + +# Some things are only necessary when we're in snapshot mode. +if [ "${SNAPSHOT:+set}" = "set" ]; then + # The snapshot branch only gets the spin number bumped. + bump_mode_to="${release}-$(( SPIN + 1 ))~dev" + + # The local integration branch only gets its DATE bumped. Ask `date` to + # figure out what the next month is. Use mid-month as a starting point to + # allow `date` to compute with accuracy. + bump_int_date="$(date -d "$(date -d "${DATE//./-}-15" +%Y-%m-%d) +1 month" +%Y.%m)" + + # For next month on the integration branch there is no SPIN number. + bump_int_to="${vstring%.*}-${bump_int_date}~dev" + + # Due to a change in the GCC branch naming policy, all new GCC releases + # start with a single digit release. + if [ ${vstring%%.*} -ge "5" ]; then + int_vstring=${vstring%%.*} + else + # The 4.[1-9] branches have the .[digit] in the branch name. + int_vstring=${vstring%.*} + fi + + # This is the local branch where we bump the gcc/LINARO-VERSION to indicate + # the next month. We don't need ~dev in the local int branch name. This + # will not be used when respinning. + local_int_branch="snapshots/gcc-${int_vstring}-integration-branch-${bump_int_to%\~dev}" + + # At the end of the script it will recommend that changes to the + # local_int_branch will be pushed to the remote_int_branch. + remote_int_branch="remotes/${REMOTE}/linaro-local/gcc-${int_vstring}-integration-branch" +elif [ "${CANDIDATE:+set}" = "set" ]; then + bump_mode_to="${release}${SPIN:+-${SPIN}}-rc$(( RC + 1 ))~dev" +else + bump_mode_to="${release}-$(( SPIN + 1 ))-rc$(( RC + 1 ))~dev" +fi + +# The local branch can have the SPIN number on the name. +local_branch=${SNAPSHOT:+snapshots/}${RELEASE:+releases/}${CANDIDATE:+releases/}linaro-${release}${SPIN:+-$SPIN}${CANDIDATE:+-rc${RC}} + +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 + +# Release candidates and releases always push against the future or current +# release branch. Snapshots always go into the snapshots namespace. +remote_mode_branch="remotes/${REMOTE}/linaro-local/${SNAPSHOT:+snapshots}${RELEASE:+releases}${CANDIDATE:+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:+-${SPIN}}${CANDIDATE:+-rc${RC}}" + +# Differentiate between Snapshots and Releases, depending on what's set. +rname=${SNAPSHOT:+snapshot-}$release +chglmsg="GCC Linaro ${release} ${SNAPSHOT:+snapshot}${RELEASE:+release}${CANDIDATE:+release candidate}." +commitmsg="Make Linaro GCC ${SNAPSHOT:+Snapshot }${RELEASE:+Release }${CANDIDATE:+Release Candidate }${release}." + +#Remove 'Make' for the front, and '.' from the back for the tag message. +tagmsg=${commitmsg#Make } +tagmsg=${tagmsg%.} +release_tag="linaro-${rname}" + +REL_DIR="$PWD" + + +# ============================================================================== +# Prepare Sources +# ============================================================================== + +info +echo -e "\n\n" + +print_info "${bold}Checking out branch \"${local_branch}\"..." +git checkout -B ${local_branch} ${track} 2>/dev/null + +print_info "${bold}Creating ${SNAPSHOT:+snapshot}${RELEASE:+release}${CANDIDATE:+release candidate} ChangeLog entries..." + +changelog + +print_info "${bold}The following commit was made when updating the ChangeLog entries." + +# Display the changes from the ChangeLog commit. +git --no-pager show -n 1 ${local_branch} 2>/dev/null +# Empty line seems appropriate for visual continuity. +echo "" + +tag + +if [[ "${SNAPSHOT:+set}" = "set" && "${SPIN:+set}" != "set" ]]; then + print_info "${bold}Checking out branch \"${local_int_branch}\"..." + git checkout -B ${local_int_branch} ${local_branch} 1>/dev/null + + # Bump the integration branch gcc/LINARO-VERSION + bump_and_dev "${bump_int_to}" +fi + +print_info "${bold}Checking out branch \"${local_branch}\"..." +git checkout ${local_branch} 1>/dev/null +bump_and_dev "${bump_mode_to}" + +git push ${REMOTE} "${release_tag}" || clean_and_die "Couldn't push tag: ${release_tag}" +git push ${REMOTE} "${local_branch}:${remote_mode_branch/remotes\/${REMOTE}/refs/heads}" || clean_and_die "Couldn't push branch: ${local_branch}" + +if [[ "${SNAPSHOT:+set}" = "set" && "${SPIN:+set}" != "set" ]]; then + git push ${REMOTE} "${local_int_branch}:${remote_int_branch/remotes\/${REMOTE}/refs/heads}" || clean_and_die "Couldn't push branch: ${local_int_branch}" +fi diff --git a/tcwg-release-tarball.sh b/tcwg-release-tarball.sh new file mode 100755 index 0000000..2222b0d --- /dev/null +++ b/tcwg-release-tarball.sh @@ -0,0 +1,159 @@ +#!/bin/bash + +# Style +NC='\e[0m' +red='\e[0;31m' +blue='\e[1;34m' +green='\e[0;32m' +bold='\e[1m' +italic='\e[3m' +# ============================================================================== +# Usage and Help +# ============================================================================== +usage() { + # Format this section with 75 columns. + cat << EOF + ${src_tarball_script} [-g GIT_TREE] [-h] [-r REL_DIR] [-t TAG] [-u] +EOF + return 0 +} + +# ============================================================================== +# Functions +# ============================================================================== +print_info() { + echo -e "${blue}** ${NC}${1}${NC}" +} + +die() { + echo -e "${red}${bold}ERROR: ${NC}${bold}${1}${NC}" + exit 1 +} + +# ============================================================================== +# Settings +# ============================================================================== + +# Clear the directory stack so a popd in clean() always returns us to the right +# place. +dirs -c + +export GIT_WORK_TREE="$PWD" +REL_DIR="$PWD/../release" + +src_tarball_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 ":g:hr:t:u" options +do + case $options in + g ) GIT_WORK_TREE="$OPTARG" + ;; + h ) usage; exit 1; + ;; + r ) REL_DIR="$(readlink -f "$OPTARG")" + ;; + t ) TAG="$OPTARG" + ;; + u ) usage; exit 1; + ;; + \?) print_info "Option -${BOLD}$OPTARG${NC} Unsupported." + ;; + : ) usage; die "Option \"-$OPTARG\" requires an argument." + ;; + esac +done + +if [ $# -lt 1 ]; then + usage +fi + +shift $(( OPTIND - 1 )) + +export GIT_DIR="$GIT_WORK_TREE"/.git +if [ ! -d "${GIT_WORK_TREE}/gcc" ]; then + die "${GIT_WORK_TREE} is not the top-level GCC source directory." +fi + +# Test to make sure the branch or tag exists +git rev-parse --abbrev-ref $TAG &>/dev/null || die "Tag \"$TAG\" doesn't exist." + +# Keep track of the branch we start from because we'll want to return there at +# the end or if we have to cleanup prematurely. +save_branch="$(git rev-parse --abbrev-ref HEAD)" + +vstring=$(git show "$TAG":gcc/BASE-VER) +release=${vstring%.*}-"$DATE" +REL_DIR="${REL_DIR}/gcc-${TAG}" + +# Terminal lines (minus 7 to account for interesting prior output. +terminal_lines=$(( $(tput lines) - 7 )) + +# ============================================================================== +# Checkout and Export +# ============================================================================== +print_info "${bold}Checking out tag \"${TAG}\"..." +git checkout "${TAG}" 2>/dev/null + +print_info "${bold}Exporting sources from git..." +git checkout-index -f -a --prefix=$REL_DIR/gcc-${TAG}/ + +pushd $REL_DIR/gcc-${TAG} 1>/dev/null + +# ============================================================================== +# Generate ChangeLog.linaro from git commit messages for GCC branches >= 5 +# ============================================================================== +if [ ${vstring%%.*} -ge "5" ]; then + print_info "${bold}Generating ChangeLog.linaro from git commit messages..." + SINCE=$(git log --format=%H --grep="git-svn-id" | head -n 1) + mydir="$(dirname "$(readlink -f "$0")")" + if [ ${vstring%%.*} -eq "5" ]; then + gitlog_amend="--amend ${mydir}/gitlog-amend-gcc-5" + else + gitlog_amend="" + fi + ${mydir}/gitlog-to-changelog --since ${SINCE} --no-cluster \ + --strip-change-id --format=%B --strip-tab \ + ${gitlog_amend} > $REL_DIR/gcc-${TAG}/ChangeLog.linaro +fi + +git checkout "$save_branch" &>/dev/null + +# ============================================================================== +# GCC Build +# ============================================================================== +print_info "${bold}Building GCC..." +env SOURCEDIR="$PWD/gcc/doc" DESTDIR="$PWD/INSTALL" ./gcc/doc/install.texi2html || die "Failed to build documentation." +env MAKE="make -j4" contrib/gcc_build -d $REL_DIR/gcc-${TAG} \ + -o $REL_DIR/objdir -c \ + "--enable-generated-files-in-srcdir --disable-multilib" build || die "Failed to build GCC." +mv -v $REL_DIR/objdir/gcc/po/*.gmo $REL_DIR/gcc-${TAG}/gcc/po/ || die "Failed to move gmo files" + +# ============================================================================== +# MD5SUM +# ============================================================================== +print_info "${bold}Creating tarball's files MD5 checksums..." +cat - >MD5SUMS <<EOF +# This file contains the MD5 checksums of the files in the +# gcc-${TAG}.tar.xz tarball. +# +# Besides verifying that all files in the tarball were correctly expanded, +# it also can be used to determine if any files have changed since the +# tarball was expanded or to verify that a patchfile was correctly applied. +# +# Suggested usage: +# md5sum -c MD5SUMS | grep -v "OK$" +EOF +find . -type f | sed -e 's:^\./::' -e '/MD5SUMS/d' | LC_ALL=C sort | xargs md5sum >>MD5SUMS + +# ============================================================================== +# Create tarball +# ============================================================================== +popd 1>/dev/null +pushd $REL_DIR 1>/dev/null +print_info "${bold}Creating tarball gcc-${TAG}.tar.xz..." +tar cfJ gcc-${TAG}.tar.xz gcc-${TAG} +md5sum gcc-${TAG}.tar.xz > gcc-${TAG}.tar.xz.asc +popd 1>/dev/null + |