1#! /usr/bin/env bash
2
3set -euo pipefail
4
5if [ "$1" != "package" ]; then
6  if (grep -r KJ_DBG c++/src | egrep -v '/debug(-test)?[.]' | grep -v 'See KJ_DBG\.$'); then
7    echo '*** Error:  There are instances of KJ_DBG in the code.' >&2
8    exit 1
9  fi
10
11  if (egrep -r 'TODO\((now|soon)\)' *); then
12    echo '*** Error:  There are release-blocking TODOs in the code.' >&2
13    exit 1
14  fi
15fi
16
17doit() {
18  echo "@@@@ $@"
19  "$@"
20}
21
22get_version() {
23  local VERSION=$(grep '^AC_INIT' c++/configure.ac | sed -e 's/^[^]]*],\[\([^]]*\)].*$/\1/g')
24  if [[ ! "$VERSION" =~ $1 ]]; then
25    echo "Couldn't parse version: $VERSION" >&2
26    exit 1
27  fi
28  echo "$VERSION"
29}
30
31get_release_version() {
32  get_version '^[0-9]+[.][0-9]+[.][0-9]+(-rc[0-9]+|[.][0-9]+)?$'
33}
34
35update_version() {
36  local OLD=$1
37  local NEW=$2
38  local BRANCH_DESC=$3
39
40  local OLD_REGEX=${OLD//./[.]}
41  doit sed -i -e "s/$OLD_REGEX/$NEW/g" c++/configure.ac
42  doit sed -i -e "s/set(VERSION.*)/set(VERSION $NEW)/g" c++/CMakeLists.txt
43
44  local NEW_NOTAG=${NEW%%-*}
45  declare -a NEW_ARR=(${NEW_NOTAG//./ })
46  doit sed -i -re "
47      s/^#define CAPNP_VERSION_MAJOR [0-9]+\$/#define CAPNP_VERSION_MAJOR ${NEW_ARR[0]}/g;
48      s/^#define CAPNP_VERSION_MINOR [0-9]+\$/#define CAPNP_VERSION_MINOR ${NEW_ARR[1]}/g;
49      s/^#define CAPNP_VERSION_MICRO [0-9]+\$/#define CAPNP_VERSION_MICRO ${NEW_ARR[2]:-0}/g" \
50      c++/src/capnp/common.h
51
52  local NEW_COMBINED=$(( ${NEW_ARR[0]} * 1000000 + ${NEW_ARR[1]} * 1000 + ${NEW_ARR[2]:-0 }))
53  doit sed -i -re "s/^#if CAPNP_VERSION != [0-9]*\$/#if CAPNP_VERSION != $NEW_COMBINED/g" \
54      c++/src/*/*.capnp.h c++/src/*/*/*.capnp.h
55
56  doit git commit -a -m "Set $BRANCH_DESC version to $NEW."
57}
58
59build_packages() {
60  local VERSION=$1
61  local VERSION_BASE=${VERSION%%-*}
62
63  echo "========================================================================="
64  echo "Building C++ package..."
65  echo "========================================================================="
66
67  # make dist tarball and move into ..
68  cd c++
69  doit autoreconf -i
70  doit ./configure
71  doit make -j6 distcheck
72  doit mv capnproto-c++-$VERSION.tar.gz ..
73  doit make distclean
74
75  # build windows executables
76  doit ./configure --host=i686-w64-mingw32 --with-external-capnp \
77      --disable-shared CXXFLAGS='-static-libgcc -static-libstdc++'
78  doit make -j6 capnp.exe capnpc-c++.exe capnpc-capnp.exe
79  doit i686-w64-mingw32-strip capnp.exe capnpc-c++.exe capnpc-capnp.exe
80  doit mkdir capnproto-tools-win32-$VERSION
81  doit mv capnp.exe capnpc-c++.exe capnpc-capnp.exe capnproto-tools-win32-$VERSION
82  doit make maintainer-clean
83
84  # repack dist tarball and win32 tools into win32 zip, with DOS line endings
85  doit tar zxf ../capnproto-c++-$VERSION.tar.gz
86  find capnproto-c++-$VERSION -name '*.c++' -o -name '*.h' -o -name '*.capnp' -o -name '*.md' -o -name '*.txt' | grep -v testdata | doit xargs unix2dos
87  doit zip -r ../capnproto-c++-win32-$VERSION.zip capnproto-c++-$VERSION capnproto-tools-win32-$VERSION
88
89  rm -rf capnproto-c++-$VERSION capnproto-tools-win32-$VERSION
90  cd ..
91}
92
93cherry_pick() {
94  shift
95  if [ $# -gt 0 ]; then
96    echo "========================================================================="
97    echo "Cherry-picking fixes"
98    echo "========================================================================="
99    doit git cherry-pick "$@"
100  fi
101}
102
103done_banner() {
104  local VERSION=$1
105  local PUSH=$2
106  local FINAL=$3
107  echo "========================================================================="
108  echo "Done"
109  echo "========================================================================="
110  echo "Ready to release:"
111  echo "  capnproto-c++-$VERSION.tar.gz"
112  echo "  capnproto-c++-win32-$VERSION.zip"
113  echo "Don't forget to push changes:"
114  echo "  git push origin $PUSH"
115
116  read -s -n 1 -p "Shall I push to git and upload to capnproto.org now? (y/N)" YESNO
117
118  echo
119  case "$YESNO" in
120    y | Y )
121      doit git push origin $PUSH
122      doit gce-ss copy-files capnproto-c++-$VERSION.tar.gz capnproto-c++-win32-$VERSION.zip \
123          alpha2:/var/www/capnproto.org
124
125      if [ "$FINAL" = yes ]; then
126        echo "========================================================================="
127        echo "Publishing docs"
128        echo "========================================================================="
129        cd doc
130        doit ./push-site.sh
131        cd ..
132        echo "========================================================================="
133        echo "Really done"
134        echo "========================================================================="
135      fi
136
137      echo "Release is available at:"
138      echo "  http://capnproto.org/capnproto-c++-$VERSION.tar.gz"
139      ;;
140    * )
141      echo "OK, do it yourself then."
142      ;;
143  esac
144}
145
146BRANCH=$(git rev-parse --abbrev-ref HEAD)
147
148case "${1-}:$BRANCH" in
149  # ======================================================================================
150  candidate:master )
151    echo "New major release."
152
153    if [ $# -gt 1 ]; then
154      echo "Cannot cherry-pick when starting from master.  Do it yourself." >&2
155      exit 1
156    fi
157
158    HEAD_VERSION=$(get_version '^[0-9]+[.][0-9]+-dev$')
159    RELEASE_VERSION=${HEAD_VERSION%%-dev}.0
160
161    echo "Version: $RELEASE_VERSION"
162
163    echo "========================================================================="
164    echo "Creating release branch..."
165    echo "========================================================================="
166    doit git checkout -b release-$RELEASE_VERSION
167
168    update_version $HEAD_VERSION $RELEASE_VERSION-rc1 "release branch"
169
170    build_packages $RELEASE_VERSION-rc1
171
172    echo "========================================================================="
173    echo "Updating version in master branch..."
174    echo "========================================================================="
175
176    doit git checkout master
177    declare -a VERSION_ARR=(${RELEASE_VERSION//./ })
178    NEXT_VERSION=${VERSION_ARR[0]}.$((VERSION_ARR[1] + 1))
179
180    update_version $HEAD_VERSION $NEXT_VERSION-dev "mainline"
181
182    done_banner $RELEASE_VERSION-rc1 "master release-$RELEASE_VERSION" no
183    ;;
184
185  # ======================================================================================
186  candidate:release-* )
187    echo "New release candidate."
188    OLD_VERSION=$(get_release_version)
189
190    if [[ $OLD_VERSION == *-rc* ]]; then
191      # New release candidate for existing release.
192
193      RC=${OLD_VERSION##*-rc}
194      BRANCH_VERSION=${OLD_VERSION%%-rc*}
195      RC_VERSION=$BRANCH_VERSION-rc$(( RC + 1 ))
196
197      echo "Version: $RC_VERSION"
198    else
199      # New micro release.
200
201      declare -a VERSION_ARR=(${OLD_VERSION//./ })
202      BRANCH_VERSION=${VERSION_ARR[0]}.${VERSION_ARR[1]}.$((VERSION_ARR[2] + 1))
203
204      RC_VERSION=$BRANCH_VERSION-rc1
205      echo "Version: $RC_VERSION"
206
207      echo "========================================================================="
208      echo "Creating new release branch..."
209      echo "========================================================================="
210
211      doit git checkout -b release-$BRANCH_VERSION
212    fi
213
214    echo "========================================================================="
215    echo "Updating version number to $RC_VERSION..."
216    echo "========================================================================="
217
218    update_version $OLD_VERSION $RC_VERSION "release branch"
219
220    cherry_pick "$@"
221
222    build_packages $RC_VERSION
223
224    done_banner $RC_VERSION release-$BRANCH_VERSION no
225    ;;
226
227  # ======================================================================================
228  final:release-* )
229    echo "Final release."
230    OLD_VERSION=$(get_release_version)
231
232    if [[ $OLD_VERSION != *-rc* ]]; then
233      echo "Current version is already a final release.  You need to create a new candidate first." >&2
234      exit 1
235    fi
236
237    if [ $# -gt 1 ]; then
238      echo "Cannot cherry-pick into final release.  Make another candidate." >&2
239      exit 1
240    fi
241
242    RC=${OLD_VERSION##*-rc}
243    NEW_VERSION=${OLD_VERSION%%-rc*}
244
245    echo "Version: $NEW_VERSION"
246
247    echo "========================================================================="
248    echo "Updating version number to $NEW_VERSION..."
249    echo "========================================================================="
250
251    doit sed -i -re "s/capnproto-c[+][+]-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-$NEW_VERSION/g" doc/install.md
252    doit sed -i -re "s/capnproto-c[+][+]-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-win32-$NEW_VERSION/g" doc/install.md
253    doit sed -i -re "s/capnproto-tools-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-tools-win32-$NEW_VERSION/g" doc/install.md
254    update_version $OLD_VERSION $NEW_VERSION "release branch"
255
256    doit git tag v$NEW_VERSION
257
258    build_packages $NEW_VERSION
259
260    done_banner $NEW_VERSION "v$NEW_VERSION release-$NEW_VERSION" yes
261    ;;
262
263  # ======================================================================================
264  security:release-* )
265    echo "Security release."
266    OLD_VERSION=$(get_release_version)
267
268    if [[ $OLD_VERSION == *-rc* ]]; then
269      echo "Security releases don't have candidates." >&2
270      exit 1
271    fi
272
273    declare -a VERSION_ARR=(${OLD_VERSION//./ } 0)
274    NEW_VERSION=${VERSION_ARR[0]}.${VERSION_ARR[1]}.${VERSION_ARR[2]}.$((VERSION_ARR[3] + 1))
275
276    echo "Version: $NEW_VERSION"
277
278    echo "========================================================================="
279    echo "Updating version number to $NEW_VERSION..."
280    echo "========================================================================="
281
282    doit sed -i -re "s/capnproto-c[+][+]-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-$NEW_VERSION/g" doc/install.md
283    doit sed -i -re "s/capnproto-c[+][+]-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-win32-$NEW_VERSION/g" doc/install.md
284    doit sed -i -re "s/capnproto-tools-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-tools-win32-$NEW_VERSION/g" doc/install.md
285    update_version $OLD_VERSION $NEW_VERSION "release branch"
286
287    cherry_pick "$@"
288
289    doit git tag v$NEW_VERSION
290
291    build_packages $NEW_VERSION
292
293    done_banner $NEW_VERSION "v$NEW_VERSION release-$NEW_VERSION" yes
294    ;;
295
296  # ======================================================================================
297  retry:release-* )
298    echo "Retrying release."
299    OLD_VERSION=$(get_release_version)
300    echo "Version: $OLD_VERSION"
301
302    if [[ $OLD_VERSION == *-rc* ]]; then
303      # We can add more cherry-picks when retrying a candidate.
304      cherry_pick "$@"
305    else
306      if [ $# -gt 1 ]; then
307        echo "Cannot cherry-pick into final release.  Make another candidate." >&2
308        exit 1
309      fi
310    fi
311
312    OLD_VERSION=$(get_release_version)
313    build_packages $OLD_VERSION
314
315    if [[ $OLD_VERSION == *-rc* ]]; then
316      BRANCH_VERSION=${OLD_VERSION%%-rc*}
317      done_banner $OLD_VERSION release-$BRANCH_VERSION no
318    else
319      doit git tag v$OLD_VERSION
320      done_banner $OLD_VERSION "v$OLD_VERSION release-$OLD_VERSION" no
321    fi
322    ;;
323
324  # ======================================================================================
325  package:* )
326    echo "Just building a package."
327    build_packages $(get_version '.*')
328    ;;
329
330  # ======================================================================================
331  *:master )
332    echo "Invalid command for mainline branch.  Only command is 'candidate'." >&2
333    exit 1
334    ;;
335
336  *:release-* )
337    echo "Invalid command for release branch.  Commands are 'candidate', 'final', and 'retry'." >&2
338    exit 1
339    ;;
340
341  * )
342    echo "Not a master or release branch." >&2
343    exit 1
344    ;;
345esac
346