Update copyright statements. Make it easier to sync with Jim Tcl
[openocd.git] / tools / release.sh
blobf1ed4a73ada15cfeccfb53e518faf66b273f5d50
1 #!/bin/sh -e
2 # release.sh: openocd release process automation
3 # Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net>
4 # Release under the GNU GPL v2 (or later versions).
6 ## set these to control the build process
7 #CONFIG_OPTS=""
8 #MAKE_OPTS=""
10 ## DO NOT PERFORM LIVE RELEASES UNLESS YOU ARE THE RELEASE MANAGER!!!
11 RELEASE_DRY_RUN=1
12 ## set this to perform individual steps on past releases
13 RELEASE_VERSION=
15 die() {
16 echo "$@" >&2
17 exit 1
20 svn_info_get() {
21 svn info | grep "$1" | cut -d':' -f2- | cut -c2-
24 svn_setup_load() {
25 SVN_ROOT="$(svn_info_get 'Repository Root')"
26 SVN_URL="$(svn_info_get 'URL')"
28 SVN_TRUNK="${SVN_ROOT}/trunk"
30 SVN_BRANCHES="${SVN_ROOT}/branches"
31 PACKAGE_BRANCH="${SVN_BRANCHES}/${PACKAGE_RELEASE}"
33 SVN_TAGS="${SVN_ROOT}/tags"
34 PACKAGE_TAG="${SVN_TAGS}/${PACKAGE_RELEASE}"
36 if [ "${SVN_URL}" = "${SVN_TRUNK}" ]; then
37 RELEASE_TYPE=minor
38 elif [ "${SVN_URL/${SVN_BRANCHES}/}" != "${SVN_URL}" ]; then
39 RELEASE_TYPE=micro
40 else
41 echo "error: bad URL: ${SVN_URL}" >&2
42 die "unable to branch from the current location"
45 svn_setup_show() {
46 cat <<INFO
47 Release Type: ${RELEASE_TYPE}
48 Branch URL: ${PACKAGE_BRANCH}
49 Tag URL: ${PACKAGE_TAG}
50 INFO
53 do_svn_echo_msg() { echo "svn: $1: $3"; }
54 do_svn_echo() {
55 case "$1" in
56 commit)
57 do_svn_echo_msg "$@"
58 shift 3
59 [ "$*" ] && echo "Files: $@"
61 copy|move)
62 do_svn_echo_msg "$@"
63 echo "From: ${4:-$2}"
64 echo " To: ${5:-$3}"
67 local ACTION="$1"
68 shift
69 echo "svn: ${ACTION}: $@"
71 esac
73 do_svn() {
74 do_svn_echo "$@"
75 [ "${RELEASE_DRY_RUN}" ] || svn "$@"
77 do_svn_switch() {
78 do_svn switch "$@"
79 package_info_load
83 package_info_load_name() {
84 grep AC_INIT configure.in | perl -ne 's/^.+\(\[([-\w]*)\],.+$/$1/ and print'
86 package_info_load_version() {
87 grep AC_INIT configure.in | perl -ne 's/^.+\[([-\w\.]*)\],$/$1/ and print'
90 package_info_load() {
91 [ -f "configure.in" ] || \
92 die "package_info_load: configure.in is missing"
94 PACKAGE_NAME="$(package_info_load_name)"
95 # todo: fix this
96 PACKAGE_TARNAME="${PACKAGE_NAME}"
98 PACKAGE_VERSION="$(package_info_load_version)"
99 [ "${RELEASE_VERSION}" ] || \
100 RELEASE_VERSION=${PACKAGE_VERSION/-dev/}
102 [ "${PACKAGE_NAME}" -a "${PACKAGE_VERSION}" ] || \
103 die "package information is missing from configure script"
105 PACKAGE_VERSION_TAGS=
106 [ "${PACKAGE_VERSION/-/}" = "${PACKAGE_VERSION}" ] || \
107 PACKAGE_VERSION_TAGS="-${PACKAGE_VERSION#*-}"
108 PACKAGE_VERSION_BASE="${PACKAGE_VERSION%%-*}"
109 PACKAGE_MICRO="${PACKAGE_VERSION_BASE##*.}"
110 PACKAGE_MAJOR_AND_MINOR="${PACKAGE_VERSION_BASE%.*}"
111 PACKAGE_MAJOR="${PACKAGE_MAJOR_AND_MINOR%.*}"
112 PACKAGE_MINOR="${PACKAGE_MAJOR_AND_MINOR#*.}"
114 PACKAGE_STRING="${PACKAGE_NAME} ${PACKAGE_VERSION}"
115 if [ "${RELEASE_DRY_RUN}" ]; then
116 PACKAGE_RELEASE="${PACKAGE_TARNAME}-${PACKAGE_VERSION}"
117 else
118 PACKAGE_RELEASE="${PACKAGE_TARNAME}-${RELEASE_VERSION}"
122 package_info_show() {
123 cat <<INFO
124 Name: ${PACKAGE_TARNAME}
125 Release: ${RELEASE_VERSION}
126 Version: ${PACKAGE_VERSION}
127 Number: ${PACKAGE_VERSION_BASE}
128 Series: ${PACKAGE_MAJOR_AND_MINOR}
129 Major: ${PACKAGE_MAJOR}
130 Minor: ${PACKAGE_MINOR}
131 Micro: ${PACKAGE_MICRO}
132 Tags: ${PACKAGE_VERSION_TAGS}
133 Branch: ${PACKAGE_RELEASE}
134 Release: ${PACKAGE_TARNAME}-${PACKAGE_VERSION_BASE}${PACKAGE_VERSION_TAGS}
135 INFO
138 usage() {
139 cat << USAGE
140 usage: $0 <command>
142 Main Commands:
143 info Show a summary of the next pending release.
144 release Release the current tree as an archive.
145 upload Upload archives to berliOS project site
147 Build Commands:
148 bootstrap Prepare the working copy for configuration and building.
149 configure Configures the package; runs bootstrap, if needed.
150 build Compiles the project; runs configure, if needed.
152 Packaging Commands:
153 changelog Generate a new ChangeLog using svn2cl.
154 package Produce new distributable source archives.
155 stage Move archives to staging area for upload.
157 Repository Commands:
158 commit Perform branch and tag, as appropriate for the version.
159 branch Create a release branch from the project trunk.
160 tag Create a tag for the current release branch.
162 Other Commands:
163 version ... Perform version number and tag manipulations.
164 maryslamb Mary had a little lamb, but no one noticed.
165 clean Forces regeneration of results.
166 clean_all Removes all traces of the release process.
167 help Provides this list of commands.
169 For more information about this script, see the Release Processes page
170 in the OpenOCD Developer's Manual (doc/manual/release.txt).
172 WARNING: This script should be used by the Release Manager ONLY.
173 USAGE
174 exit 0
176 do_usage() { usage; }
177 do_help() { usage; }
179 do_info_show() {
180 echo "Current Release Analysis:"
181 package_info_show
182 svn_setup_show
185 do_info() {
186 package_info_load
187 svn_setup_load
188 do_info_show
191 do_bootstrap() {
192 echo -n "Bootstrapping..."
193 ./bootstrap 2>&1 | perl tools/logger.pl > "release-bootstrap.log"
195 maybe_bootstrap() { [ -f "configure" ] || do_bootstrap; }
197 do_configure() {
198 maybe_bootstrap
199 echo -n "Configuring..."
200 ./configure ${CONFIG_OPTS} 2>&1 | perl tools/logger.pl > "release-config.log"
202 maybe_configure() { [ -f "Makefile" ] || do_configure; }
204 do_build() {
205 maybe_configure
206 echo -n "Compiling OpenOCD ${PACKAGE_VERSION}"
207 make ${MAKE_OPTS} -C doc stamp-vti 2>&1 \
208 | perl tools/logger.pl > "release-version.log"
209 make ${MAKE_OPTS} 2>&1 \
210 | perl tools/logger.pl > "release-make.log"
212 maybe_build() { [ -f "src/openocd" ] || do_build; }
213 do_build_clean() { [ -f Makefile ] && make maintainer-clean >/dev/null; }
215 do_changelog() {
216 echo "Updating working copy to HEAD..."
217 do_svn update
218 echo "Creating ChangeLog..."
219 svn2cl -i --authors AUTHORS.ChangeLog
221 maybe_changelog() {
222 if [ -z "${RELEASE_DRY_RUN}" ] \
223 || [ ! -f ChangeLog ] \
224 || [ "$(cat ChangeLog | wc -l)" -lt 2 ]
225 then
226 do_changelog
229 do_changelog_clean() {
230 do_svn revert ChangeLog
233 do_package() {
234 package_info_load
235 maybe_changelog
236 maybe_build
237 echo "Building distribution packages..."
238 make ${MAKE_OPTS} distcheck 2>&1 | perl tools/logger.pl > "release-pkg.log"
240 maybe_package() { [ -f "${PACKAGE_RELEASE}.zip" ] || do_package; }
241 do_package_clean() {
242 for EXT in tar.gz tar.bz2 zip; do
243 rm -v -f *.${EXT}
244 done
247 do_stage() {
248 maybe_package
249 echo "Staging package archives:"
250 mkdir -p archives
251 for EXT in tar.gz tar.bz2 zip; do
252 local FILE="${PACKAGE_RELEASE}.${EXT}"
253 # create archive signatures
254 for HASH in md5 sha1; do
255 echo "sign: ${FILE}.${HASH}"
256 ${HASH}sum "${FILE}" > "archives/${FILE}.${HASH}"
257 done
258 # save archive
259 mv -v "${FILE}" archives/
260 done
261 cp -a NEWS archives/
262 cp -a ChangeLog archives/
264 do_stage_clean() { rm -v -f -r archives; }
266 do_clean() {
267 do_build_clean
268 do_package_clean
269 rm -v -f configure
271 svn revert configure.in
272 rm -v -f release-*.log
274 do_clean_all() {
275 do_clean
276 do_changelog_clean
277 do_stage_clean
280 do_version_usage() {
281 cat << USAGE
282 usage: $0 version <command>
283 Version Commands:
284 tag {add|remove} <label> Add or remove the specified tag.
285 bump {major|minor|micro} Bump the specified version number, and
286 reset less-significant numbers to zero.
287 bump tag <label> Add or bump a versioned tag (e.g. -rcN).
288 bump final <label> Remove a versioned tag (e.g. -rcN).
289 USAGE
292 do_version_sed() {
293 local OLD_VERSION="${PACKAGE_VERSION}"
294 local NEW_VERSION="$1"
295 local MSG="$2"
297 sed -i -e "/AC_INIT/ s|${OLD_VERSION}|${NEW_VERSION}|" configure.in
298 package_info_load
299 echo "${MSG}: ${OLD_VERSION} -> ${NEW_VERSION}"
301 do_version_bump_sed() {
302 local NEW_VERSION="$1"
303 [ -z "${PACKAGE_VERSION_TAGS}" ] || \
304 NEW_VERSION="${NEW_VERSION}${PACKAGE_VERSION_TAGS}"
306 do_version_sed "${NEW_VERSION}" \
307 "Bump ${CMD} package version number"
309 do_version_bump_major() {
310 do_version_bump_sed "$((PACKAGE_MAJOR + 1)).0.0"
312 do_version_bump_minor() {
313 do_version_bump_sed "${PACKAGE_MAJOR}.$((PACKAGE_MINOR + 1)).0"
315 do_version_bump_micro() {
316 do_version_bump_sed "${PACKAGE_MAJOR_AND_MINOR}.$((PACKAGE_MICRO + 1))"
318 do_version_bump_tag() {
319 local TAG="$1"
320 [ "${TAG}" ] || die "TAG argument is missing"
321 local TAGS="${PACKAGE_VERSION_TAGS}"
322 if has_version_tag "${TAG}"; then
323 local RC=$(do_version_tag_value "${TAG}")
324 RC=$((${RC} + 1))
325 TAGS=$(echo ${TAGS} | perl -npe "s/-${TAG}[\\d]*/-${TAG}${RC}/")
326 else
327 TAGS="-${TAG}1${PACKAGE_VERSION_TAGS}"
329 PACKAGE_VERSION_TAGS="${TAGS}"
330 do_version_bump_sed "${PACKAGE_VERSION_BASE}"
332 do_version_bump_final() {
333 local TAG="$1"
334 [ "${TAG}" ] || die "TAG argument is missing"
335 has_version_tag "${TAG}" || die "-${TAG} tag is missing"
336 do_version_tag_remove "${TAG}$(do_version_tag_value "${TAG}")"
338 do_version_bump() {
339 CMD="$1"
340 shift
341 case "${CMD}" in
342 major|minor|micro|final|tag)
343 eval "do_version_bump_${CMD}" "$@"
346 do_version_usage
348 esac
351 has_version_tag() {
352 test "${PACKAGE_VERSION/-${1}/}" != "${PACKAGE_VERSION}"
354 do_version_tag_value() {
355 local TAG="$1"
356 echo ${PACKAGE_VERSION_TAGS} | perl -ne "/-${TAG}"'(\d+)/ && print $1'
358 do_version_tag_add() {
359 local TAG="$1"
360 has_version_tag "${TAG}" && \
361 die "error: tag '-${TAG}' exists in '${PACKAGE_VERSION}'"
362 do_version_sed "${PACKAGE_VERSION}-${TAG}" \
363 "Add '-${TAG}' version tag"
365 do_version_tag_remove() {
366 local TAG="$1"
367 has_version_tag "${TAG}" || \
368 die "error: tag '-${TAG}' missing from '${PACKAGE_VERSION}'"
369 do_version_sed "${PACKAGE_VERSION/-${TAG}/}" \
370 "Remove '-${TAG}' version tag"
372 do_version_tag() {
373 CMD="$1"
374 shift
375 case "${CMD}" in
376 add|remove)
377 local i=
378 for i in "$@"; do
379 eval "do_version_tag_${CMD}" "${i}"
380 done
383 do_version_usage
385 esac
388 do_version_commit() {
389 [ "$(svn diff configure.in | wc -l)" -gt 0 ] || \
390 die "error: no version changes to commit"
391 do_svn commit -m "$1" configure.in
394 do_version() {
395 package_info_load
396 CMD="$1"
397 shift
398 case "${CMD}" in
399 tag|bump)
400 do_version_commit "$(eval "do_version_${CMD}" "$@")"
402 commit)
403 local MSG="$1"
404 [ "${MSG}" ] || die "usage: $0 version commit <message>"
405 do_version_commit "${MSG}"
408 do_version_usage
410 esac
414 do_branch() {
415 package_info_load
416 svn_setup_load
417 do_svn copy -m "Branching version ${PACKAGE_VERSION}" \
418 "${SVN_TRUNK}" "${PACKAGE_BRANCH}"
420 do_tag() {
421 package_info_load
422 svn_setup_load
423 do_svn copy -m "Tagging version ${PACKAGE_VERSION}" \
424 "${PACKAGE_BRANCH}" "${PACKAGE_TAG}"
426 do_commit() {
427 package_info_load
428 svn_setup_load
430 [ "${PACKAGE_VERSION/dev/}" = "${PACKAGE_VERSION}" ] || \
431 die "'${PACKAGE_NAME}-${PACKAGE_VERSION}' cannot be released"
433 [ "${PACKAGE_VERSION%.0}" = "${PACKAGE_VERSION}" ] || \
434 do_branch
435 do_tag
439 do_release_step_prep() {
440 do_version tag remove dev
441 # reset RELEASE_VERSION now to allow release version to be detected
442 export RELEASE_VERSION=
444 do_release_step_commit() { do_commit; }
446 do_release_step_branch_bump() {
447 local TYPE="$1"
448 echo "Bump ${TYPE} version and add tag:"
449 do_version_bump ${TYPE}
450 do_version_tag_add dev
452 do_release_step_branch() {
453 do_svn_switch "${PACKAGE_BRANCH}"
454 do_version_commit "$(do_release_step_branch_bump micro)"
455 do_svn_switch "${SVN_URL}"
457 do_release_step_news_msg() {
458 cat <<MSG
459 Archive released NEWS file: NEWS -> NEWS-${RELEASE_VERSION}
460 Create new NEWS file from relesse script template.
463 do_release_step_news() {
464 # archive NEWS and create new one from template
465 do_svn move "NEWS" "NEWS-${RELEASE_VERSION}"
467 [ "${RELEASE_DRY_RUN}" ] || cat >NEWS <<NEWS
468 This file should include items worth mentioning in the
469 OpenOCD ${PACKAGE_RELEASE} source archive release.
471 The following areas of OpenOCD functionality changed in this release:
473 JTAG Layer:
474 Target Layer:
475 Flash Layer:
476 Board, Target, and Interface Configuration Scripts:
477 Documentation:
478 Build and Release:
480 For more details about what has changed since the last release,
481 see the ChangeLog associated with this source archive. For older NEWS,
482 see the NEWS files associated with each release (i.e. NEWS-<version>).
484 For more information about contributing test reports, bug fixes, or new
485 features and device support, please read the new Developer Manual (or
486 the BUGS and PATCHES files in the source archive).
487 NEWS
488 do_svn add NEWS
490 local MSG="$(do_release_step_news_msg)"
491 do_svn commit -m "${MSG}" NEWS NEWS-${RELEASE_VERSION}
493 do_release_step_bump() {
494 # major and minor releases require branch version update too
495 [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_branch
496 # bump the current tree version as required.
497 do_version_commit "$(do_release_step_branch_bump "${RELEASE_TYPE}")"
499 [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_news
501 do_release_step_package() {
502 local A=${PACKAGE_TAG}
503 local B=${A/https/http}
504 local PACKAGE_BUILD=${B/${USER}@/}
506 do_svn_switch "${PACKAGE_TAG}"
507 do_svn_switch --relocate "${PACKAGE_TAG}" "${PACKAGE_BUILD}"
509 # required to force SVN to update the in-source URL keyword
510 [ "${RELEASE_DRY_RUN}" ] || rm -v -f src/openocd.c
511 do_svn revert src/openocd.c
513 do_stage
514 do_clean
516 do_svn_switch --relocate "${PACKAGE_BUILD}" "${PACKAGE_TAG}"
517 do_svn_switch "${SVN_URL}"
520 do_release_step_1() { do_release_step_prep; }
521 do_release_step_2() { do_release_step_commit; }
522 do_release_step_3() { do_release_step_bump; }
523 do_release_step_4() { do_release_step_package; }
525 do_release_check() {
526 echo -n "Are you sure you want to release '${PACKAGE_RELEASE}'?"
527 read ANSWER
528 if [ "${ANSWER}" != 'y' ]; then
529 echo "Live release aborted!"
530 exit 0
533 do_countdown() {
534 echo -n "$1 in "
535 for i in $(seq 5 -1 1); do
536 echo -n "$i, "
537 done
538 echo "go!"
541 do_release() {
542 package_info_load
543 package_info_show
545 if [ -z "${RELEASE_DRY_RUN}" ]; then
546 do_release_check
547 do_countdown "Starting live release"
550 local i=
551 for i in $(seq 1 4); do
552 eval "do_release_step_${i}"
553 done
555 do_all() { do_release "$@"; }
557 do_reset() {
558 maybe_bootstrap
559 maybe_configure
560 do_clean_all
561 svn revert configure.in
564 OPTIONS=$(getopt -o V --long live -n $0 -- "$@")
565 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
566 eval set -- "${OPTIONS}"
567 while true; do
568 case "$1" in
569 --live)
570 export RELEASE_DRY_RUN=
571 shift
574 exec $0 info
577 shift
578 break
581 echo "Internal error"
582 exit 1
584 esac
585 done
587 CMD=$1
588 [ "${CMD}" ] || usage
589 shift
591 ACTION_CMDS="bootstrap|configure|build|changelog|package|stage|clean"
592 MISC_CMDS="all|info|version|tag|branch|commit|release|reset|help|usage"
593 CLEAN_CMDS="build_clean|changelog_clean|package_clean|stage_clean|clean_all"
594 CMDS="|${ACTION_CMDS}|${CLEAN_CMDS}|${MISC_CMDS}|"
595 is_command() { echo "${CMDS}" | grep "|$1|" >/dev/null; }
597 if is_command "${CMD}"; then
598 eval "do_${CMD}" "$@"
599 else
600 echo "error: unknown command: '${CMD}'"
601 usage