summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtcwg-release-tag.sh741
-rwxr-xr-xtcwg-release-tarball.sh159
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
+