diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/release.sh | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/tools/release.sh b/tools/release.sh new file mode 100755 index 00000000..583cd20c --- /dev/null +++ b/tools/release.sh @@ -0,0 +1,569 @@ +#!/bin/sh -e +# release.sh: openocd release process automation +# Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> +# Release under the GNU GPL v2 (or later versions). + +## set these to control the build process +#CONFIG_OPTS="" +#MAKE_OPTS="" + +## DO NOT PERFORM LIVE RELEASES UNLESS YOU ARE THE RELEASE MANAGER!!! +RELEASE_DRY_RUN=1 +## set this to perform individual steps on past releases +RELEASE_VERSION= + +die() { + echo "$@" >&2 + exit 1 +} + +svn_info_get() { + svn info | grep "$1" | cut -d':' -f2- | cut -c2- +} + +svn_setup_load() { + SVN_ROOT="$(svn_info_get 'Repository Root')" + SVN_URL="$(svn_info_get 'URL')" + + SVN_TRUNK="${SVN_ROOT}/trunk" + + SVN_BRANCHES="${SVN_ROOT}/branches" + PACKAGE_BRANCH="${SVN_BRANCHES}/${PACKAGE_RELEASE}" + + SVN_TAGS="${SVN_ROOT}/tags" + PACKAGE_TAG="${SVN_TAGS}/${PACKAGE_RELEASE}" + + if [ "${SVN_URL}" = "${SVN_TRUNK}" ]; then + RELEASE_TYPE=minor + elif [ "${SVN_URL/${SVN_BRANCHES}/}" != "${SVN_URL}" ]; then + RELEASE_TYPE=micro + else + echo "error: bad URL: ${SVN_URL}" >&2 + die "unable to branch from the current location" + fi +} +svn_setup_show() { + cat <<INFO +Release Type: ${RELEASE_TYPE} + Branch URL: ${PACKAGE_BRANCH} + Tag URL: ${PACKAGE_TAG} +INFO +} + +do_svn_echo_msg() { echo "svn: $1: $3"; } +do_svn_echo() { + case "$1" in + commit) + do_svn_echo_msg "$@" + shift 3 + [ "$*" ] && echo "Files: $@" + ;; + copy|move) + do_svn_echo_msg "$@" + echo "From: ${4:-$2}" + echo " To: ${5:-$3}" + ;; + *) + local ACTION="$1" + shift + echo "svn: ${ACTION}: $@" + ;; + esac +} +do_svn() { + do_svn_echo "$@" + [ "${RELEASE_DRY_RUN}" ] || svn "$@" +} + + +package_info_load_name() { + grep AC_INIT configure.in | perl -ne 's/^.+\(\[([-\w]*)\],.+$/$1/ and print' +} +package_info_load_version() { + grep AC_INIT configure.in | perl -ne 's/^.+\[([-\w\.]*)\],$/$1/ and print' +} + +package_info_load() { + [ -f "configure.in" ] || \ + die "package_info_load: configure.in is missing" + + PACKAGE_NAME="$(package_info_load_name)" + # todo: fix this + PACKAGE_TARNAME="${PACKAGE_NAME}" + + PACKAGE_VERSION="$(package_info_load_version)" + [ "${RELEASE_VERSION}" ] || \ + RELEASE_VERSION=${PACKAGE_VERSION/-in-development/} + + [ "${PACKAGE_NAME}" -a "${PACKAGE_VERSION}" ] || \ + die "package information is missing from configure script" + + PACKAGE_VERSION_TAGS= + [ "${PACKAGE_VERSION/-/}" = "${PACKAGE_VERSION}" ] || \ + PACKAGE_VERSION_TAGS="-${PACKAGE_VERSION#*-}" + PACKAGE_VERSION_BASE="${PACKAGE_VERSION%%-*}" + PACKAGE_MICRO="${PACKAGE_VERSION_BASE##*.}" + PACKAGE_MAJOR_AND_MINOR="${PACKAGE_VERSION_BASE%.*}" + PACKAGE_MAJOR="${PACKAGE_MAJOR_AND_MINOR%.*}" + PACKAGE_MINOR="${PACKAGE_MAJOR_AND_MINOR#*.}" + + PACKAGE_STRING="${PACKAGE_NAME} ${PACKAGE_VERSION}" + if [ "${RELEASE_DRY_RUN}" ]; then + PACKAGE_RELEASE="${PACKAGE_TARNAME}-${PACKAGE_VERSION}" + else + PACKAGE_RELEASE="${PACKAGE_TARNAME}-${RELEASE_VERSION}" + fi +} + +package_info_show() { + cat <<INFO +Name: ${PACKAGE_TARNAME} +Release: ${RELEASE_VERSION} +Version: ${PACKAGE_VERSION} + Number: ${PACKAGE_VERSION_BASE} + Series: ${PACKAGE_MAJOR_AND_MINOR} + Major: ${PACKAGE_MAJOR} + Minor: ${PACKAGE_MINOR} + Micro: ${PACKAGE_MICRO} + Tags: ${PACKAGE_VERSION_TAGS} + Branch: ${PACKAGE_RELEASE} +Release: ${PACKAGE_TARNAME}-${PACKAGE_VERSION_BASE}${PACKAGE_VERSION_TAGS} +INFO +} + +usage() { + cat << USAGE +usage: $0 <command> + +Main Commands: + info Show a summary of the next pending release. + release Release the current tree as an archive. + upload Upload archives to berliOS project site + +Build Commands: + bootstrap Prepare the working copy for configuration and building. + configure Configures the package; runs bootstrap, if needed. + build Compiles the project; runs configure, if needed. + +Packaging Commands: + changelog Generate a new ChangeLog using svn2cl. + package Produce new distributable source archives. + stage Move archives to staging area for upload. + +Repository Commands: + commit Perform branch and tag, as appropriate for the version. + branch Create a release branch from the project trunk. + tag Create a tag for the current release branch. + +Other Commands: + version ... Perform version number and tag manipulations. + maryslamb Mary had a little lamb, but no one noticed. + clean Forces regeneration of results. + clean_all Removes all traces of the release process. + help Provides this list of commands. + +For more information about this script, see the Release Processes page +in the OpenOCD Developer's Manual (doc/manual/release.txt). + +WARNING: This script should be used by the Release Manager ONLY. +USAGE + exit 0 +} +do_usage() { usage; } +do_help() { usage; } + +do_info_show() { + echo "Current Release Analysis:" + package_info_show + svn_setup_show +} + +do_info() { + package_info_load + svn_setup_load + do_info_show +} + +do_bootstrap() { + echo -n "Bootstrapping..." + ./bootstrap 2>&1 | perl tools/logger.pl > "release-bootstrap.log" +} +maybe_bootstrap() { [ -f "configure" ] || do_bootstrap; } + +do_configure() { + maybe_bootstrap + echo -n "Configuring..." + ./configure ${CONFIG_OPTS} 2>&1 | perl tools/logger.pl > "release-config.log" +} +maybe_configure() { [ -f "Makefile" ] || do_configure; } + +do_build() { + maybe_configure + echo -n "Compiling OpenOCD ${PACKAGE_VERSION}" + make ${MAKE_OPTS} -C doc stamp-vti 2>&1 \ + | perl tools/logger.pl > "release-version.log" + make ${MAKE_OPTS} 2>&1 \ + | perl tools/logger.pl > "release-make.log" +} +maybe_build() { [ -f "src/openocd" ] || do_build; } +do_build_clean() { [ -f Makefile ] && make maintainer-clean >/dev/null; } + +maybe_rebuild() { + if [ -f "configure" ]; then + echo "Re-running autoconf..." + autoconf + echo "Re-running automake..." + automake + fi + if [ -f "Makefile" ]; then + do_configure + do_build + fi +} + +do_changelog() { + echo "Updating working copy to HEAD..." + do_svn update + echo "Creating ChangeLog..." + svn2cl -i --authors AUTHORS.ChangeLog +} +maybe_changelog() { + if [ -z "${RELEASE_DRY_RUN}" ] \ + || [ ! -f ChangeLog ] \ + || [ "$(cat ChangeLog | wc -l)" -lt 2 ] + then + do_changelog + fi +} +do_changelog_clean() { + do_svn revert ChangeLog +} + +do_package() { + package_info_load + maybe_changelog + maybe_build + echo "Building distribution packages..." + make ${MAKE_OPTS} distcheck 2>&1 | perl tools/logger.pl > "release-pkg.log" +} +maybe_package() { [ -f "${PACKAGE_RELEASE}.zip" ] || do_package; } +do_package_clean() { + for EXT in tar.gz tar.bz2 zip; do + rm -v -f *.${EXT} + done +} + +do_stage() { + maybe_package + echo "Staging package archives:" + mkdir -p archives + for EXT in tar.gz tar.bz2 zip; do + mv -v "${PACKAGE_RELEASE}.${EXT}" archives/ + done + cp -a NEWS archives/ + cp -a ChangeLog archives/ +} +do_stage_clean() { rm -v -f -r archives; } + +do_clean() { + do_build_clean + do_package_clean + rm -v -f configure + + svn revert configure.in + rm -v -f release-*.log +} +do_clean_all() { + do_clean + do_changelog_clean + do_stage_clean +} + +do_version_usage() { + cat << USAGE +usage: $0 version <command> +Version Commands: + tag {add|remove} <label> Add or remove the specified tag. + bump {major|minor|micro|rc} Bump the specified version number; + resets less-significant numbers to zero. + All but 'rc' releases drop that tag. +USAGE +} + +do_version_sed() { + local OLD_VERSION="${PACKAGE_VERSION}" + local NEW_VERSION="$1" + local MSG="$2" + + sed -i -e "/AC_INIT/ s|${OLD_VERSION}|${NEW_VERSION}|" configure.in + package_info_load + echo "${MSG}: ${OLD_VERSION} -> ${NEW_VERSION}" +} +do_version_bump_sed() { + local NEW_VERSION="$1" + [ -z "${PACKAGE_VERSION_TAGS}" ] || \ + NEW_VERSION="${NEW_VERSION}${PACKAGE_VERSION_TAGS}" + + do_version_sed "${NEW_VERSION}" \ + "Bump ${CMD} package version number" +} +do_version_bump_major() { + has_version_tag 'rc\d' do_version_ + do_version_bump_sed "$((PACKAGE_MAJOR + 1)).0.0" +} +do_version_bump_minor() { + do_version_bump_sed "${PACKAGE_MAJOR}.$((PACKAGE_MINOR + 1)).0" +} +do_version_bump_micro() { + do_version_bump_sed "${PACKAGE_MAJOR_AND_MINOR}.$((PACKAGE_MICRO + 1))" +} +do_version_bump_rc() { + die "patch missing: -rc support is not implemented" +} +do_version_bump() { + CMD="$1" + shift + case "${CMD}" in + major|minor|micro|rc) + eval "do_version_bump_${CMD}" + ;; + *) + do_version_usage + ;; + esac +} + +has_version_tag() { + test "${PACKAGE_VERSION/-${TAG}/}" != "${PACKAGE_VERSION}" +} + +do_version_tag_add() { + local TAG="$1" + has_version_tag && die "error: tag '-${TAG}' exists in '${PACKAGE_VERSION}'" + do_version_sed "${PACKAGE_VERSION}-${TAG}" \ + "Add '-${TAG}' version tag" +} +do_version_tag_remove() { + local TAG="$1" + has_version_tag || die "error: tag '-${TAG}' missing from '${PACKAGE_VERSION}'" + do_version_sed "${PACKAGE_VERSION/-${TAG}/}" \ + "Remove '-${TAG}' version tag" +} +do_version_tag() { + CMD="$1" + shift + case "${CMD}" in + add|remove) + local i= + for i in "$@"; do + eval "do_version_tag_${CMD}" "${i}" + done + ;; + *) + do_version_usage + ;; + esac +} + +do_version_commit() { + [ "$(svn diff configure.in | wc -l)" -gt 0 ] || \ + die "error: no version changes to commit" + do_svn commit -m "$1" configure.in +} + +do_version() { + package_info_load + CMD="$1" + shift + case "${CMD}" in + tag|bump) + do_version_commit "$(eval "do_version_${CMD}" "$@")" + maybe_rebuild + ;; + commit) + local MSG="$1" + [ "${MSG}" ] || die "usage: $0 version commit <message>" + do_version_commit "${MSG}" + maybe_rebuild + ;; + *) + do_version_usage + ;; + esac +} + + +do_branch() { + package_info_load + svn_setup_load + do_svn copy -m "Branching version ${PACKAGE_VERSION}" \ + "${SVN_TRUNK}" "${PACKAGE_BRANCH}" +} +do_tag() { + package_info_load + svn_setup_load + do_svn copy -m "Tagging version ${PACKAGE_VERSION}" \ + "${PACKAGE_BRANCH}" "${PACKAGE_TAG}" +} +do_commit() { + package_info_load + svn_setup_load + + [ "${PACKAGE_VERSION/in-development/}" = "${PACKAGE_VERSION}" ] || \ + die "'${PACKAGE_NAME}-${PACKAGE_VERSION}' cannot be released" + + [ "${PACKAGE_VERSION%.0}" = "${PACKAGE_VERSION}" ] || \ + do_branch + do_tag +} + + +do_release_step_prep() { + do_version tag remove in-development + # reset RELEASE_VERSION now to allow release version to be detected + export RELEASE_VERSION= +} +do_release_step_commit() { do_commit; } + +do_release_step_branch_bump() { + local TYPE="$1" + echo "Bump ${TYPE} version and add tag:" + do_version_bump ${TYPE} + do_version_tag_add in-development +} +do_release_step_branch() { + do_svn switch "${PACKAGE_BRANCH}" + package_info_load + do_version_commit "$(do_release_step_branch_bump micro)" + do_svn switch "${SVN_URL}" + package_info_load +} +do_release_step_bump() { + # major and minor releases require branch version update too + [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_branch + # bump the current tree version as required. + do_version_commit "$(do_release_step_branch_bump "${RELEASE_TYPE}")" + + # archive NEWS and create new one from template + do_svn move "NEWS" "NEWS-${RELEASE_VERSION}" + + [ "${RELEASE_DRY_RUN}" ] || cat >NEWS <<NEWS +This file should include items worth mentioning in the +OpenOCD ${PACKAGE_RELEASE} source archive release. + +The following areas of OpenOCD functionality changed in this release: + +JTAG Layer: +Target Layer: +Flash Layer: +Board, Target, and Interface Configuration Scripts: +Documentation: +Build and Release: + +For more details about what has changed since the last release, +see the ChangeLog associated with this source archive. For older NEWS, +see the NEWS files associated with each release (i.e. NEWS-<version>). + +For more information about contributing test reports, bug fixes, or new +features and device support, please read the new Developer Manual (or +the BUGS and PATCHES files in the source archive). +NEWS + + MSG=<<MSG +Archive released NEWS file: NEWS -> NEWS-${RELEASE_VERSION} +Create new NEWS file from relesse script template. +MSG + do_svn commit -m "${MSG}" NEWS NEWS-${RELEASE_VERSION} +} +do_release_step_package() { + local A=${PACKAGE_TAG} + local B=${A/https/http} + local PACKAGE_BUILD=${B/${USER}@/} + do_svn switch "${PACKAGE_BUILD}" + do_stage + do_clean +} + +do_release_step_1() { do_release_step_prep; } +do_release_step_2() { do_release_step_commit; } +do_release_step_3() { do_release_step_bump; } +do_release_step_4() { do_release_step_package; } + +do_release_check() { + echo -n "Are you sure you want to release '${PACKAGE_RELEASE}'?" + read ANSWER + if [ "${ANSWER}" != 'y' ]; then + echo "Live release aborted!" + exit 0 + fi +} +do_countdown() { + echo -n "$1 in " + for i in $(seq 5 -1 1); do + echo -n "$i, " + done + echo "go!" +} + +do_release() { + package_info_load + package_info_show + + if [ -z "${RELEASE_DRY_RUN}" ]; then + do_release_check + do_countdown "Starting live release" + fi + + local i= + for i in $(seq 1 4); do + eval "do_release_step_${i}" + done +} +do_all() { do_release "$@"; } + +do_reset() { + maybe_bootstrap + maybe_configure + do_clean_all + svn revert configure.in +} + +OPTIONS=$(getopt -o V --long live -n $0 -- "$@") +if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi +eval set -- "${OPTIONS}" +while true; do + case "$1" in + --live) + export RELEASE_DRY_RUN= + shift + ;; + -V) + exec $0 info + ;; + --) + shift + break + ;; + *) + echo "Internal error" + exit 1 + ;; + esac +done + +CMD=$1 +[ "${CMD}" ] || usage +shift + +ACTION_CMDS="bootstrap|configure|build|changelog|package|stage|clean" +MISC_CMDS="all|info|version|tag|branch|commit|release|reset|help|usage" +CLEAN_CMDS="build_clean|changelog_clean|package_clean|stage_clean|clean_all" +CMDS="|${ACTION_CMDS}|${CLEAN_CMDS}|${MISC_CMDS}|" +is_command() { echo "${CMDS}" | grep "|$1|" >/dev/null; } + +if is_command "${CMD}"; then + eval "do_${CMD}" "$@" +else + echo "error: unknown command: '${CMD}'" + usage +fi |