]> git.sur5r.net Git - openocd/blob - tools/release.sh
Improve the release script before 0.2.0:
[openocd] / tools / release.sh
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).
5
6 ## set these to control the build process
7 #CONFIG_OPTS=""
8 #MAKE_OPTS=""
9
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=
14
15 die() {
16         echo "$@" >&2
17         exit 1
18 }
19
20 svn_info_get() {
21         svn info | grep "$1" | cut -d':' -f2- | cut -c2-
22 }
23
24 svn_setup_load() {
25         SVN_ROOT="$(svn_info_get 'Repository Root')"
26         SVN_URL="$(svn_info_get 'URL')"
27
28         SVN_TRUNK="${SVN_ROOT}/trunk"
29
30         SVN_BRANCHES="${SVN_ROOT}/branches"
31         PACKAGE_BRANCH="${SVN_BRANCHES}/${PACKAGE_RELEASE}"
32
33         SVN_TAGS="${SVN_ROOT}/tags"
34         PACKAGE_TAG="${SVN_TAGS}/${PACKAGE_RELEASE}"
35
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"
43         fi
44 }
45 svn_setup_show() {
46         cat <<INFO
47 Release Type: ${RELEASE_TYPE}
48   Branch URL: ${PACKAGE_BRANCH}
49      Tag URL: ${PACKAGE_TAG}
50 INFO
51 }
52
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: $@"
60                 ;;
61         copy|move)
62                 do_svn_echo_msg "$@"
63                 echo "From: ${4:-$2}"
64                 echo "  To: ${5:-$3}"
65                 ;;
66         *)
67                 local ACTION="$1"
68                 shift
69                 echo "svn: ${ACTION}: $@"
70                 ;;
71         esac
72 }
73 do_svn() {
74         do_svn_echo "$@"
75         [ "${RELEASE_DRY_RUN}" ] || svn "$@"
76 }
77 do_svn_switch() {
78         do_svn switch "$1"
79         package_info_load
80 }
81
82
83 package_info_load_name() {
84         grep AC_INIT configure.in | perl -ne 's/^.+\(\[([-\w]*)\],.+$/$1/ and print'
85 }
86 package_info_load_version() {
87         grep AC_INIT configure.in | perl -ne 's/^.+\[([-\w\.]*)\],$/$1/ and print'
88 }
89
90 package_info_load() {
91         [ -f "configure.in" ] || \
92                 die "package_info_load: configure.in is missing"
93
94         PACKAGE_NAME="$(package_info_load_name)"
95         # todo: fix this
96         PACKAGE_TARNAME="${PACKAGE_NAME}"
97
98         PACKAGE_VERSION="$(package_info_load_version)"
99         [ "${RELEASE_VERSION}" ] || \
100                 RELEASE_VERSION=${PACKAGE_VERSION/-in-development/}
101
102         [ "${PACKAGE_NAME}" -a "${PACKAGE_VERSION}" ] || \
103                 die "package information is missing from configure script"
104
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#*.}"
113
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}"
119         fi
120 }
121
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
136 }
137
138 usage() {
139         cat << USAGE
140 usage: $0 <command>
141
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
146
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.
151
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.
156
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.
161
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.
168   
169 For more information about this script, see the Release Processes page
170 in the OpenOCD Developer's Manual (doc/manual/release.txt).
171
172 WARNING: This script should be used by the Release Manager ONLY.
173 USAGE
174         exit 0
175 }
176 do_usage() { usage; }
177 do_help()  { usage; }
178
179 do_info_show() {
180         echo "Current Release Analysis:"
181         package_info_show
182         svn_setup_show
183 }
184
185 do_info() {
186         package_info_load
187         svn_setup_load
188         do_info_show
189 }
190
191 do_bootstrap() {
192         echo -n "Bootstrapping..."
193         ./bootstrap 2>&1 | perl tools/logger.pl > "release-bootstrap.log"
194 }
195 maybe_bootstrap() { [ -f "configure" ] || do_bootstrap; }
196
197 do_configure() {
198         maybe_bootstrap
199         echo -n "Configuring..."
200         ./configure ${CONFIG_OPTS} 2>&1 | perl tools/logger.pl > "release-config.log"
201 }
202 maybe_configure() { [ -f "Makefile" ] || do_configure; }
203
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"
211 }
212 maybe_build() { [ -f "src/openocd" ] || do_build; }
213 do_build_clean() { [ -f Makefile ] && make maintainer-clean >/dev/null; }
214
215 maybe_rebuild() {
216         if [ -f "configure" ]; then
217                 echo "Re-running autoconf..."
218                 autoconf
219                 echo "Re-running automake..."
220                 automake
221         fi
222         if [ -f "Makefile" ]; then
223                 do_configure
224                 do_build
225         fi
226 }
227
228 do_changelog() {
229         echo "Updating working copy to HEAD..."
230         do_svn update
231         echo "Creating ChangeLog..."
232         svn2cl -i --authors AUTHORS.ChangeLog
233 }
234 maybe_changelog() {
235         if [ -z "${RELEASE_DRY_RUN}" ] \
236                 || [ ! -f ChangeLog ] \
237                 || [ "$(cat ChangeLog | wc -l)" -lt 2 ]
238         then
239                 do_changelog
240         fi
241 }
242 do_changelog_clean() {
243         do_svn revert ChangeLog
244 }
245
246 do_package() {
247         package_info_load
248         maybe_changelog
249         maybe_build
250         echo "Building distribution packages..."
251         make ${MAKE_OPTS} distcheck 2>&1 | perl tools/logger.pl > "release-pkg.log"
252 }
253 maybe_package() { [ -f "${PACKAGE_RELEASE}.zip" ] || do_package; }
254 do_package_clean() {
255         for EXT in tar.gz tar.bz2 zip; do
256                 rm -v -f *.${EXT}
257         done
258 }
259
260 do_stage() {
261         maybe_package
262         echo "Staging package archives:"
263         mkdir -p archives
264         for EXT in tar.gz tar.bz2 zip; do
265                 mv -v "${PACKAGE_RELEASE}.${EXT}" archives/
266         done
267         cp -a NEWS archives/
268         cp -a ChangeLog archives/
269 }
270 do_stage_clean() { rm -v -f -r archives; }
271
272 do_clean() {
273         do_build_clean
274         do_package_clean
275         rm -v -f configure
276
277         svn revert configure.in
278         rm -v -f release-*.log
279 }
280 do_clean_all() {
281         do_clean
282         do_changelog_clean
283         do_stage_clean
284 }
285
286 do_version_usage() {
287         cat << USAGE
288 usage: $0 version <command>
289 Version Commands:
290   tag {add|remove} <label>     Add or remove the specified tag.
291   bump {major|minor|micro|rc}  Bump the specified version number;
292                                resets less-significant numbers to zero.
293                                All but 'rc' releases drop that tag.
294 USAGE
295 }
296
297 do_version_sed() {
298         local OLD_VERSION="${PACKAGE_VERSION}"
299         local NEW_VERSION="$1"
300         local MSG="$2"
301
302         sed -i -e "/AC_INIT/ s|${OLD_VERSION}|${NEW_VERSION}|" configure.in
303         package_info_load
304         echo "${MSG}: ${OLD_VERSION} -> ${NEW_VERSION}"
305 }
306 do_version_bump_sed() {
307         local NEW_VERSION="$1"
308         [ -z "${PACKAGE_VERSION_TAGS}" ] || \
309                 NEW_VERSION="${NEW_VERSION}${PACKAGE_VERSION_TAGS}"
310
311         do_version_sed "${NEW_VERSION}" \
312                 "Bump ${CMD} package version number"
313 }
314 do_version_bump_major() {
315         has_version_tag 'rc\d' do_version_
316         do_version_bump_sed "$((PACKAGE_MAJOR + 1)).0.0"
317 }
318 do_version_bump_minor() {
319         do_version_bump_sed "${PACKAGE_MAJOR}.$((PACKAGE_MINOR + 1)).0"
320 }
321 do_version_bump_micro() {
322         do_version_bump_sed "${PACKAGE_MAJOR_AND_MINOR}.$((PACKAGE_MICRO + 1))"
323 }
324 do_version_bump_rc() {
325         die "patch missing: -rc support is not implemented"
326 }
327 do_version_bump() {
328         CMD="$1"
329         shift
330         case "${CMD}" in
331         major|minor|micro|rc)
332                 eval "do_version_bump_${CMD}"
333                 ;;
334         *)
335                 do_version_usage
336                 ;;
337         esac
338 }
339
340 has_version_tag() {
341         test "${PACKAGE_VERSION/-${TAG}/}" != "${PACKAGE_VERSION}"
342 }
343
344 do_version_tag_add() {
345         local TAG="$1"
346         has_version_tag && die "error: tag '-${TAG}' exists in '${PACKAGE_VERSION}'"
347         do_version_sed "${PACKAGE_VERSION}-${TAG}" \
348                 "Add '-${TAG}' version tag"
349 }
350 do_version_tag_remove() {
351         local TAG="$1"
352         has_version_tag || die "error: tag '-${TAG}' missing from '${PACKAGE_VERSION}'"
353         do_version_sed "${PACKAGE_VERSION/-${TAG}/}" \
354                 "Remove '-${TAG}' version tag"
355 }
356 do_version_tag() {
357         CMD="$1"
358         shift
359         case "${CMD}" in
360         add|remove)
361                 local i=
362                 for i in "$@"; do 
363                         eval "do_version_tag_${CMD}" "${i}"
364                 done
365                 ;;
366         *)
367                 do_version_usage
368                 ;;
369         esac
370 }
371
372 do_version_commit() {
373         [ "$(svn diff configure.in | wc -l)" -gt 0 ] || \
374                 die "error: no version changes to commit"
375         do_svn commit -m "$1" configure.in
376 }
377
378 do_version() {
379         package_info_load
380         CMD="$1"
381         shift
382         case "${CMD}" in
383         tag|bump)
384                 do_version_commit "$(eval "do_version_${CMD}" "$@")"
385                 maybe_rebuild
386                 ;;
387         commit)
388                 local MSG="$1"
389                 [ "${MSG}" ] || die "usage: $0 version commit <message>"
390                 do_version_commit "${MSG}"
391                 maybe_rebuild
392                 ;;
393         *)
394                 do_version_usage
395                 ;;
396         esac
397 }
398
399
400 do_branch() {
401         package_info_load
402         svn_setup_load
403         do_svn copy -m "Branching version ${PACKAGE_VERSION}" \
404                 "${SVN_TRUNK}" "${PACKAGE_BRANCH}"
405 }
406 do_tag() {
407         package_info_load
408         svn_setup_load
409         do_svn copy -m "Tagging version ${PACKAGE_VERSION}" \
410                 "${PACKAGE_BRANCH}" "${PACKAGE_TAG}"
411 }
412 do_commit() {
413         package_info_load
414         svn_setup_load
415
416         [ "${PACKAGE_VERSION/in-development/}" = "${PACKAGE_VERSION}" ] || \
417                 die "'${PACKAGE_NAME}-${PACKAGE_VERSION}' cannot be released"
418
419         [ "${PACKAGE_VERSION%.0}" = "${PACKAGE_VERSION}" ] || \
420                 do_branch
421         do_tag
422 }
423
424
425 do_release_step_prep() {
426         do_version tag remove in-development
427         # reset RELEASE_VERSION now to allow release version to be detected
428         export RELEASE_VERSION=
429 }
430 do_release_step_commit() { do_commit; }
431
432 do_release_step_branch_bump() {
433         local TYPE="$1"
434         echo "Bump ${TYPE} version and add tag:"
435         do_version_bump ${TYPE}
436         do_version_tag_add in-development
437 }
438 do_release_step_branch() {
439         do_svn_switch "${PACKAGE_BRANCH}"
440         do_version_commit "$(do_release_step_branch_bump micro)"
441         do_svn_switch "${SVN_URL}"
442 }
443 do_release_step_bump() {
444         # major and minor releases require branch version update too
445         [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_branch
446         # bump the current tree version as required.
447         do_version_commit "$(do_release_step_branch_bump "${RELEASE_TYPE}")"
448
449         [ "${RELEASE_TYPE}" = "micro" ] && return
450
451         # archive NEWS and create new one from template
452         do_svn move "NEWS" "NEWS-${RELEASE_VERSION}"
453
454         [ "${RELEASE_DRY_RUN}" ] || cat >NEWS <<NEWS
455 This file should include items worth mentioning in the
456 OpenOCD ${PACKAGE_RELEASE} source archive release.
457
458 The following areas of OpenOCD functionality changed in this release:
459
460 JTAG Layer:
461 Target Layer:
462 Flash Layer:
463 Board, Target, and Interface Configuration Scripts:
464 Documentation:
465 Build and Release:
466
467 For more details about what has changed since the last release,
468 see the ChangeLog associated with this source archive.  For older NEWS,
469 see the NEWS files associated with each release (i.e. NEWS-<version>).
470
471 For more information about contributing test reports, bug fixes, or new
472 features and device support, please read the new Developer Manual (or
473 the BUGS and PATCHES files in the source archive).
474 NEWS
475
476         MSG=<<MSG
477 Archive released NEWS file: NEWS -> NEWS-${RELEASE_VERSION}
478 Create new NEWS file from relesse script template.
479 MSG
480         do_svn commit -m "${MSG}" NEWS NEWS-${RELEASE_VERSION}
481 }
482 do_release_step_package() {
483         local A=${PACKAGE_TAG}
484         local B=${A/https/http}
485         local PACKAGE_BUILD=${B/${USER}@/}
486         do_svn_switch "${PACKAGE_BUILD}"
487         do_stage
488         do_clean
489         do_svn_switch "${SVN_URL}"
490 }
491
492 do_release_step_1() { do_release_step_prep; }
493 do_release_step_2() { do_release_step_commit; }
494 do_release_step_3() { do_release_step_bump; }
495 do_release_step_4() { do_release_step_package; }
496
497 do_release_check() {
498         echo -n "Are you sure you want to release '${PACKAGE_RELEASE}'?"
499         read ANSWER
500         if [ "${ANSWER}" != 'y' ]; then
501                 echo "Live release aborted!"
502                 exit 0
503         fi
504 }
505 do_countdown() {
506         echo -n "$1 in "
507         for i in $(seq 5 -1 1); do
508                 echo -n "$i, "
509         done
510         echo "go!"
511 }
512
513 do_release() {
514         package_info_load
515         package_info_show
516
517         if [ -z "${RELEASE_DRY_RUN}" ]; then
518                 do_release_check
519                 do_countdown "Starting live release"
520         fi
521
522         local i=
523         for i in $(seq 1 4); do
524                 eval "do_release_step_${i}"
525         done
526 }
527 do_all() { do_release "$@"; }
528
529 do_reset() {
530         maybe_bootstrap
531         maybe_configure
532         do_clean_all
533         svn revert configure.in
534 }
535
536 OPTIONS=$(getopt -o V --long live -n $0 -- "$@")
537 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
538 eval set -- "${OPTIONS}"
539 while true; do
540         case "$1" in
541         --live)
542                 export RELEASE_DRY_RUN=
543                 shift
544                 ;;
545         -V)
546                 exec $0 info
547                 ;;
548         --)
549                 shift
550                 break
551                 ;;
552         *)
553                 echo "Internal error"
554                 exit 1
555                 ;;
556         esac
557 done
558
559 CMD=$1
560 [ "${CMD}" ] || usage
561 shift
562
563 ACTION_CMDS="bootstrap|configure|build|changelog|package|stage|clean"
564 MISC_CMDS="all|info|version|tag|branch|commit|release|reset|help|usage"
565 CLEAN_CMDS="build_clean|changelog_clean|package_clean|stage_clean|clean_all"
566 CMDS="|${ACTION_CMDS}|${CLEAN_CMDS}|${MISC_CMDS}|"
567 is_command() { echo "${CMDS}" | grep "|$1|" >/dev/null; }
568
569 if is_command "${CMD}"; then
570         eval "do_${CMD}" "$@"
571 else
572         echo "error: unknown command: '${CMD}'"
573         usage
574 fi