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.
 
 
 
 
 
 

582 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|rc} Bump the specified version number;
  248. resets less-significant numbers to zero.
  249. All but 'rc' releases drop that tag.
  250. USAGE
  251. }
  252. do_version_sed() {
  253. local OLD_VERSION="${PACKAGE_VERSION}"
  254. local NEW_VERSION="$1"
  255. local MSG="$2"
  256. sed -i -e "/AC_INIT/ s|${OLD_VERSION}|${NEW_VERSION}|" configure.in
  257. package_info_load
  258. echo "${MSG}: ${OLD_VERSION} -> ${NEW_VERSION}"
  259. }
  260. do_version_bump_sed() {
  261. local NEW_VERSION="$1"
  262. [ -z "${PACKAGE_VERSION_TAGS}" ] || \
  263. NEW_VERSION="${NEW_VERSION}${PACKAGE_VERSION_TAGS}"
  264. do_version_sed "${NEW_VERSION}" \
  265. "Bump ${CMD} package version number"
  266. }
  267. do_version_bump_major() {
  268. do_version_bump_sed "$((PACKAGE_MAJOR + 1)).0.0"
  269. }
  270. do_version_bump_minor() {
  271. do_version_bump_sed "${PACKAGE_MAJOR}.$((PACKAGE_MINOR + 1)).0"
  272. }
  273. do_version_bump_micro() {
  274. do_version_bump_sed "${PACKAGE_MAJOR_AND_MINOR}.$((PACKAGE_MICRO + 1))"
  275. }
  276. do_version_bump_rc() {
  277. die "patch missing: -rc support is not implemented"
  278. }
  279. do_version_bump() {
  280. CMD="$1"
  281. shift
  282. case "${CMD}" in
  283. major|minor|micro|rc)
  284. eval "do_version_bump_${CMD}"
  285. ;;
  286. *)
  287. do_version_usage
  288. ;;
  289. esac
  290. }
  291. has_version_tag() {
  292. test "${PACKAGE_VERSION/-${1}/}" != "${PACKAGE_VERSION}"
  293. }
  294. do_version_tag_add() {
  295. local TAG="$1"
  296. has_version_tag "${TAG}" && \
  297. die "error: tag '-${TAG}' exists in '${PACKAGE_VERSION}'"
  298. do_version_sed "${PACKAGE_VERSION}-${TAG}" \
  299. "Add '-${TAG}' version tag"
  300. }
  301. do_version_tag_remove() {
  302. local TAG="$1"
  303. has_version_tag "${TAG}" || \
  304. die "error: tag '-${TAG}' missing from '${PACKAGE_VERSION}'"
  305. do_version_sed "${PACKAGE_VERSION/-${TAG}/}" \
  306. "Remove '-${TAG}' version tag"
  307. }
  308. do_version_tag() {
  309. CMD="$1"
  310. shift
  311. case "${CMD}" in
  312. add|remove)
  313. local i=
  314. for i in "$@"; do
  315. eval "do_version_tag_${CMD}" "${i}"
  316. done
  317. ;;
  318. *)
  319. do_version_usage
  320. ;;
  321. esac
  322. }
  323. do_version_commit() {
  324. [ "$(svn diff configure.in | wc -l)" -gt 0 ] || \
  325. die "error: no version changes to commit"
  326. do_svn commit -m "$1" configure.in
  327. }
  328. do_version() {
  329. package_info_load
  330. CMD="$1"
  331. shift
  332. case "${CMD}" in
  333. tag|bump)
  334. do_version_commit "$(eval "do_version_${CMD}" "$@")"
  335. ;;
  336. commit)
  337. local MSG="$1"
  338. [ "${MSG}" ] || die "usage: $0 version commit <message>"
  339. do_version_commit "${MSG}"
  340. ;;
  341. *)
  342. do_version_usage
  343. ;;
  344. esac
  345. }
  346. do_branch() {
  347. package_info_load
  348. svn_setup_load
  349. do_svn copy -m "Branching version ${PACKAGE_VERSION}" \
  350. "${SVN_TRUNK}" "${PACKAGE_BRANCH}"
  351. }
  352. do_tag() {
  353. package_info_load
  354. svn_setup_load
  355. do_svn copy -m "Tagging version ${PACKAGE_VERSION}" \
  356. "${PACKAGE_BRANCH}" "${PACKAGE_TAG}"
  357. }
  358. do_commit() {
  359. package_info_load
  360. svn_setup_load
  361. [ "${PACKAGE_VERSION/in-development/}" = "${PACKAGE_VERSION}" ] || \
  362. die "'${PACKAGE_NAME}-${PACKAGE_VERSION}' cannot be released"
  363. [ "${PACKAGE_VERSION%.0}" = "${PACKAGE_VERSION}" ] || \
  364. do_branch
  365. do_tag
  366. }
  367. do_release_step_prep() {
  368. do_version tag remove in-development
  369. # reset RELEASE_VERSION now to allow release version to be detected
  370. export RELEASE_VERSION=
  371. }
  372. do_release_step_commit() { do_commit; }
  373. do_release_step_branch_bump() {
  374. local TYPE="$1"
  375. echo "Bump ${TYPE} version and add tag:"
  376. do_version_bump ${TYPE}
  377. do_version_tag_add in-development
  378. }
  379. do_release_step_branch() {
  380. do_svn_switch "${PACKAGE_BRANCH}"
  381. do_version_commit "$(do_release_step_branch_bump micro)"
  382. do_svn_switch "${SVN_URL}"
  383. }
  384. do_release_step_news_msg() {
  385. cat <<MSG
  386. Archive released NEWS file: NEWS -> NEWS-${RELEASE_VERSION}
  387. Create new NEWS file from relesse script template.
  388. MSG
  389. }
  390. do_release_step_news() {
  391. # archive NEWS and create new one from template
  392. do_svn move "NEWS" "NEWS-${RELEASE_VERSION}"
  393. [ "${RELEASE_DRY_RUN}" ] || cat >NEWS <<NEWS
  394. This file should include items worth mentioning in the
  395. OpenOCD ${PACKAGE_RELEASE} source archive release.
  396. The following areas of OpenOCD functionality changed in this release:
  397. JTAG Layer:
  398. Target Layer:
  399. Flash Layer:
  400. Board, Target, and Interface Configuration Scripts:
  401. Documentation:
  402. Build and Release:
  403. For more details about what has changed since the last release,
  404. see the ChangeLog associated with this source archive. For older NEWS,
  405. see the NEWS files associated with each release (i.e. NEWS-<version>).
  406. For more information about contributing test reports, bug fixes, or new
  407. features and device support, please read the new Developer Manual (or
  408. the BUGS and PATCHES files in the source archive).
  409. NEWS
  410. do_svn add NEWS
  411. local MSG="$(do_release_step_news_msg)"
  412. do_svn commit -m "${MSG}" NEWS NEWS-${RELEASE_VERSION}
  413. }
  414. do_release_step_bump() {
  415. # major and minor releases require branch version update too
  416. [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_branch
  417. # bump the current tree version as required.
  418. do_version_commit "$(do_release_step_branch_bump "${RELEASE_TYPE}")"
  419. [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_news
  420. }
  421. do_release_step_package() {
  422. local A=${PACKAGE_TAG}
  423. local B=${A/https/http}
  424. local PACKAGE_BUILD=${B/${USER}@/}
  425. do_svn_switch "${PACKAGE_TAG}"
  426. do_svn_switch --relocate "${PACKAGE_TAG}" "${PACKAGE_BUILD}"
  427. # required to force SVN to update the in-source URL keyword
  428. [ "${RELEASE_DRY_RUN}" ] || rm -v -f src/openocd.c
  429. do_svn revert src/openocd.c
  430. do_stage
  431. do_clean
  432. do_svn_switch --relocate "${PACKAGE_BUILD}" "${PACKAGE_TAG}"
  433. do_svn_switch "${SVN_URL}"
  434. }
  435. do_release_step_1() { do_release_step_prep; }
  436. do_release_step_2() { do_release_step_commit; }
  437. do_release_step_3() { do_release_step_bump; }
  438. do_release_step_4() { do_release_step_package; }
  439. do_release_check() {
  440. echo -n "Are you sure you want to release '${PACKAGE_RELEASE}'?"
  441. read ANSWER
  442. if [ "${ANSWER}" != 'y' ]; then
  443. echo "Live release aborted!"
  444. exit 0
  445. fi
  446. }
  447. do_countdown() {
  448. echo -n "$1 in "
  449. for i in $(seq 5 -1 1); do
  450. echo -n "$i, "
  451. done
  452. echo "go!"
  453. }
  454. do_release() {
  455. package_info_load
  456. package_info_show
  457. if [ -z "${RELEASE_DRY_RUN}" ]; then
  458. do_release_check
  459. do_countdown "Starting live release"
  460. fi
  461. local i=
  462. for i in $(seq 1 4); do
  463. eval "do_release_step_${i}"
  464. done
  465. }
  466. do_all() { do_release "$@"; }
  467. do_reset() {
  468. maybe_bootstrap
  469. maybe_configure
  470. do_clean_all
  471. svn revert configure.in
  472. }
  473. OPTIONS=$(getopt -o V --long live -n $0 -- "$@")
  474. if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
  475. eval set -- "${OPTIONS}"
  476. while true; do
  477. case "$1" in
  478. --live)
  479. export RELEASE_DRY_RUN=
  480. shift
  481. ;;
  482. -V)
  483. exec $0 info
  484. ;;
  485. --)
  486. shift
  487. break
  488. ;;
  489. *)
  490. echo "Internal error"
  491. exit 1
  492. ;;
  493. esac
  494. done
  495. CMD=$1
  496. [ "${CMD}" ] || usage
  497. shift
  498. ACTION_CMDS="bootstrap|configure|build|changelog|package|stage|clean"
  499. MISC_CMDS="all|info|version|tag|branch|commit|release|reset|help|usage"
  500. CLEAN_CMDS="build_clean|changelog_clean|package_clean|stage_clean|clean_all"
  501. CMDS="|${ACTION_CMDS}|${CLEAN_CMDS}|${MISC_CMDS}|"
  502. is_command() { echo "${CMDS}" | grep "|$1|" >/dev/null; }
  503. if is_command "${CMD}"; then
  504. eval "do_${CMD}" "$@"
  505. else
  506. echo "error: unknown command: '${CMD}'"
  507. usage
  508. fi