You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

603 lines
14 KiB

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