mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-02 02:34:19 +00:00
529 lines
15 KiB
Bash
Executable File
529 lines
15 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# This script builds tar, rpm, and deb packages for a new release. The
|
|
# packages are created in the release/ directory (which is created if it
|
|
# does not exist).
|
|
#
|
|
# There's only one command line option: VERISON. It must be newer than
|
|
# the last version in the Changelog; see check_version(). Do not include
|
|
# a leading 'v', just `build-packages 1.0.8' for example.
|
|
#
|
|
# These environment variables control what the script does:
|
|
# CHECK=0|1 - Do (not) check the branch, version, etc.
|
|
# UPDATE=0|1 - Do (not) update changelogs, versions, etc.
|
|
# BUILD=0|1 - Do (not) build any packages
|
|
# BUILD_TAR=0|1 - Do (not) build the .tar.gz package
|
|
# BUILD_RPM=0|1 - Do (not) build the .rpm package
|
|
# BUILD_DEB=0|1 - Do (not) build the .deb package
|
|
# All of these env vars are true by default. If, for example, you just want
|
|
# to build the branch as-is: CHECK=0 UPDATE=0 build-packages VERSION
|
|
# Otherwise, this script is pretty strict and tries to ensure a good build.
|
|
#
|
|
# These environment variables are for special builds:
|
|
# UPDATE_DOCS=0|1 - Do (not) update docs
|
|
# BETA=1 - UPDATE_DOCS=0 BUILD_RPM=0 BUILD_DEB=0
|
|
#
|
|
# A few more things you should know:
|
|
# * You'll need rpmbuild and dpkg-buildpackage to build the rpm and deb pkgs
|
|
# * Output (STDOUT and STDERR) for some stuff is saved to files in tmpdir
|
|
# * All dates/times are UTC
|
|
# * No pkgs are signed (TODO)
|
|
|
|
# ############################################################################
|
|
# Standard startup, find the branch's root directory
|
|
# ############################################################################
|
|
|
|
set -ue # bail out on errors, be strict
|
|
|
|
exit_status=0
|
|
|
|
die() {
|
|
echo "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
warn() {
|
|
echo "$1" >&2
|
|
exit_status=1
|
|
}
|
|
|
|
cwd=$PWD
|
|
PERCONA_TOOLKIT_BRANCH=${PERCONA_TOOLKIT_BRANCH:-""}
|
|
if [ -n "$PERCONA_TOOLKIT_BRANCH" ]; then
|
|
BRANCH=$PERCONA_TOOLKIT_BRANCH
|
|
cd $BRANCH
|
|
else
|
|
while [ ! -f Makefile.PL ] && [ $PWD != "/" ]; do
|
|
cd ..
|
|
done
|
|
if [ ! -f Makefile.PL ]; then
|
|
die "Cannot find the root directory of the Percona Toolkit branch"
|
|
exit 1
|
|
fi
|
|
BRANCH=`pwd`
|
|
fi
|
|
cd $cwd
|
|
|
|
# ############################################################################
|
|
# Paths
|
|
# ############################################################################
|
|
|
|
DOCS_DIR=$BRANCH/docs
|
|
SPHINX_CONFIG_DIR=$BRANCH/config/sphinx-build
|
|
DEB_CONFIG_DIR=$BRANCH/config/deb
|
|
RPM_CONFIG_DIR=$BRANCH/config/rpm
|
|
RELEASE_DIR=$BRANCH/release
|
|
|
|
# ############################################################################
|
|
# Programs and their options
|
|
# ############################################################################
|
|
|
|
TAR=${TAR:-tar}
|
|
|
|
# ############################################################################
|
|
# Subroutines
|
|
# ############################################################################
|
|
|
|
check_branch() {
|
|
echo -n "Checking branch... "
|
|
local clean_branch=$(git status --porcelain|wc -l)
|
|
if [ "$clean_branch" -gt 0 ]; then
|
|
die "The branch has uncommitted changes or unknown files"
|
|
fi
|
|
echo "OK"
|
|
}
|
|
|
|
check_version() {
|
|
echo -n "Checking new version $VERSION... "
|
|
cd $BRANCH
|
|
local current_version=$(expr `cat Makefile.PL | grep VERSION | awk '{print $3}'` : "'\([0-9.]*\)'")
|
|
if ! [ "$VERSION" '>' "$current_version" ]; then
|
|
die "New version $VERSION is not greater than current version $current_version"
|
|
fi
|
|
echo "OK"
|
|
}
|
|
|
|
check_changelog() {
|
|
echo -n "Checking Changelog... "
|
|
cd $BRANCH
|
|
first_line=$(head -n 3 Changelog | tail -n 1)
|
|
if [ $(expr "$first_line" : "v[0-9]") -gt 0 ]; then
|
|
die "No changes since $first_line"
|
|
fi
|
|
if [ -n "$(grep "^v$VERSION" Changelog)" ]; then
|
|
die "Entries for v$VERSION already exist"
|
|
fi
|
|
echo "OK"
|
|
}
|
|
|
|
check_rel_notes() {
|
|
echo -n "Checking release_notes.rst... "
|
|
cd $DOCS_DIR
|
|
if [ -n "$(grep "^v$VERSION" release_notes.rst)" ]; then
|
|
die "Entries for v$VERSION already exist"
|
|
fi
|
|
echo "OK"
|
|
}
|
|
|
|
update_version() {
|
|
echo -n "Updating version in tools... "
|
|
cd $BRANCH/bin
|
|
for tool_file in *; do
|
|
sed -i'.bak' -e "s/^$tool_file [0-9]\.[0-9][^ ]\+/$tool_file $VERSION/" $tool_file
|
|
if [ $? -ne 0 ]; then
|
|
die "Error updating version in $tool_file"
|
|
fi
|
|
rm "$tool_file.bak"
|
|
done
|
|
|
|
local new_versions=$(grep --no-filename '^pt-[^ ]\+ [0-9]\.' * | cut -d' ' -f2 | sort -u)
|
|
if [ "$new_versions" != "$VERSION" ]; then
|
|
die "The version in some tools did not update correctly"
|
|
fi
|
|
echo "OK"
|
|
|
|
echo -n "Updating version in Makefile.PL... "
|
|
cd $BRANCH
|
|
sed -i'.bak' -e "s/'[0-9.]*'/'$VERSION'/" Makefile.PL
|
|
if [ $? -ne 0 ]; then
|
|
die "Error updating version in Makefile.PL"
|
|
fi
|
|
rm "Makefile.PL.bak"
|
|
echo "OK"
|
|
|
|
echo -n "Updating version in percona-toolkit.pod... "
|
|
cd $DOCS_DIR
|
|
sed -i'.bak' -e "s/^Percona Toolkit v.*/Percona Toolkit v$VERSION released $DATE/" percona-toolkit.pod
|
|
if [ $? -ne 0 ]; then
|
|
die "Error updating version in percona-toolkit.pod"
|
|
fi
|
|
rm "percona-toolkit.pod.bak"
|
|
echo "OK"
|
|
|
|
echo -n "Updating version in sphinx-build/conf.py... "
|
|
# What Sphinx calls verison, we call series; what it calls release we
|
|
# call version.
|
|
cd $SPHINX_CONFIG_DIR
|
|
sed -i'.bak' -e "s/^version = .*/version = '$SERIES'/" conf.py
|
|
if [ $? -ne 0 ]; then
|
|
die "Error updating version in conf.py"
|
|
fi
|
|
rm "conf.py.bak"
|
|
sed -i'.bak' -e "s/^release = .*/release = '$VERSION'/" conf.py
|
|
if [ $? -ne 0 ]; then
|
|
die "Error updating release in conf.py"
|
|
fi
|
|
rm "conf.py.bak"
|
|
echo "OK"
|
|
}
|
|
|
|
update_copyright_year() {
|
|
echo -n "Updating copyright year in tools... "
|
|
cd $BRANCH/bin
|
|
for tool_file in *; do
|
|
local copyright="$(grep "[0-9] Percona LLC and/or its affiliates" $tool_file)"
|
|
local new_copyright="$(../util/new-copyright-year "$YEAR" "$copyright")"
|
|
if [ $? -ne 0 ]; then
|
|
die "Error parsing copyright year in $tool_file"
|
|
fi
|
|
sed -i'.bak' -e "s#^$copyright#$new_copyright#" $tool_file
|
|
if [ $? -ne 0 ]; then
|
|
die "Error updating copyright year in $tool_file"
|
|
fi
|
|
rm "$tool_file.bak"
|
|
done
|
|
echo "OK"
|
|
|
|
echo -n "Updating copyright year in percona-toolkit.pod... "
|
|
local pod=$DOCS_DIR/percona-toolkit.pod
|
|
local copyright="$(grep "[0-9] Percona LLC and/or its affiliates" $pod)"
|
|
local new_copyright="$(../util/new-copyright-year "$YEAR" "$copyright")"
|
|
if [ $? -ne 0 ]; then
|
|
die "Error parsing copyright year in percona-toolkit.pod"
|
|
fi
|
|
sed -i'.bak' -e "s#^$copyright#$new_copyright#" $pod
|
|
if [ $? -ne 0 ]; then
|
|
die "Error updating copyright year in percona-toolkit.pod"
|
|
fi
|
|
rm $pod.bak
|
|
echo "OK"
|
|
}
|
|
|
|
update_manifest() {
|
|
echo -n "Updating MANIFEST... "
|
|
cd $BRANCH
|
|
echo -n > MANIFEST
|
|
for file in * bin/* docs/*.pod; do
|
|
if [ -f $file ]; then
|
|
echo $file >> MANIFEST
|
|
fi
|
|
done
|
|
echo "OK"
|
|
}
|
|
|
|
update_percona_toolkit_pod() {
|
|
echo -n "Updating TOOLS section in percona-toolkit.pod... "
|
|
cd $BRANCH/bin
|
|
local pod=$DOCS_DIR/percona-toolkit.pod
|
|
local tool_list=/tmp/percona-tool-list.pod
|
|
|
|
echo "=head1 TOOLS
|
|
|
|
This release of Percona Toolkit includes the following tools:
|
|
|
|
=over
|
|
" > $tool_list
|
|
|
|
for tool in *; do
|
|
desc=$(grep -A 2 '^=head1 NAME' $tool | tail -n 1 | sed 's/ - /:/' | cut -d':' -f2)
|
|
echo "=item $tool
|
|
|
|
$desc
|
|
" >> $tool_list
|
|
done
|
|
|
|
echo "=back
|
|
|
|
For more free, open-source software developed Percona, visit
|
|
L<http://www.percona.com/software/>.
|
|
" >> $tool_list
|
|
|
|
cat $pod | ../util/replace-text -v from='^=head1 TOOLS' -v file=$tool_list -v to='^=head1' > $pod.tmp
|
|
rm $tool_list
|
|
|
|
if [ -z "$(podchecker $pod.tmp 2>&1 | grep -i 'pod syntax OK')" ]; then
|
|
die "POD syntax errors; run podchecker $pod.tmp"
|
|
fi
|
|
|
|
mv $pod.tmp $pod
|
|
echo "OK"
|
|
}
|
|
|
|
update_changelog() {
|
|
echo -n "Updating Changelog... "
|
|
cd $BRANCH
|
|
head -n 2 Changelog > /tmp/changelog.tmp
|
|
echo "v$VERSION released $DATE" >> /tmp/changelog.tmp
|
|
echo >> /tmp/changelog.tmp
|
|
n_lines=$(wc -l Changelog | awk '{print $1}')
|
|
tail -n $((n_lines - 2)) Changelog >> /tmp/changelog.tmp
|
|
mv /tmp/changelog.tmp $BRANCH/Changelog
|
|
echo "OK"
|
|
|
|
echo -n "Updating Debian changelog... "
|
|
cd $DEB_CONFIG_DIR
|
|
echo "percona-toolkit ($VERSION-1) unstable; urgency=low
|
|
" > /tmp/changelog.tmp
|
|
|
|
cat $BRANCH/Changelog | $BRANCH/util/log-entries $VERSION >> /tmp/changelog.tmp
|
|
echo >> /tmp/changelog.tmp
|
|
echo " -- Percona Toolkit Developers <toolkit-dev@percona.com> $DEB_DATE
|
|
" >> /tmp/changelog.tmp
|
|
cat changelog >> /tmp/changelog.tmp
|
|
mv /tmp/changelog.tmp changelog
|
|
echo "OK"
|
|
}
|
|
|
|
update_rel_notes() {
|
|
echo -n "Updating release_notes.rst... "
|
|
cd $DOCS_DIR
|
|
|
|
head -n 3 release_notes.rst > /tmp/release_notes.tmp
|
|
|
|
local line="v$VERSION released $DATE"
|
|
local len=${#line}
|
|
local ul="$(printf "%${len}s" | tr [:space:] '=')"
|
|
echo "$line" >> /tmp/release_notes.tmp
|
|
echo "$ul" >> /tmp/release_notes.tmp
|
|
echo >> /tmp/release_notes.tmp
|
|
(cd $cwd && cat $REL_NOTES >> /tmp/release_notes.tmp)
|
|
echo >> /tmp/release_notes.tmp
|
|
echo "Changelog" >> /tmp/release_notes.tmp
|
|
echo "---------" >> /tmp/release_notes.tmp
|
|
echo >> /tmp/release_notes.tmp
|
|
cat $BRANCH/Changelog | $BRANCH/util/log-entries $VERSION \
|
|
| sed -e 's/^ *//g' \
|
|
>> /tmp/release_notes.tmp
|
|
echo >> /tmp/release_notes.tmp
|
|
|
|
tail -n +4 release_notes.rst >> /tmp/release_notes.tmp
|
|
|
|
mv /tmp/release_notes.tmp release_notes.rst
|
|
|
|
echo "OK"
|
|
}
|
|
|
|
update_user_docs() {
|
|
echo -n "Updating user docs... "
|
|
$BRANCH/util/write-user-docs $BRANCH/bin/* > /tmp/sphinx-build.output 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
warn "Error updating user docs:"
|
|
cat /tmp/sphinx-build.output >&2
|
|
exit 1
|
|
fi
|
|
rm /tmp/sphinx-build.output
|
|
echo "OK"
|
|
}
|
|
|
|
prep_release_dir() {
|
|
echo -n "Preparing release directory... "
|
|
cd $BRANCH
|
|
if [ ! -d $RELEASE_DIR ]; then
|
|
mkdir $RELEASE_DIR
|
|
elif [ -d $RELEASE_DIR/$PKG ]; then
|
|
rm -rf $RELEASE_DIR/$PKG
|
|
fi
|
|
(
|
|
cd $RELEASE_DIR
|
|
mkdir -p $PKG $PKG/bin $PKG/docs $PKG/lib
|
|
)
|
|
for file in `cat MANIFEST`; do
|
|
cp $file $RELEASE_DIR/$PKG/$file
|
|
done
|
|
echo "OK"
|
|
}
|
|
|
|
build_tar() {
|
|
echo -n "Building $PKG.tar.gz... "
|
|
cd $RELEASE_DIR
|
|
$TAR czf "$PKG.tar.gz" $PKG
|
|
echo "OK"
|
|
}
|
|
|
|
build_rpm() {
|
|
echo -n "Building $PKG-1.noarch.rpm... "
|
|
cd $RELEASE_DIR
|
|
if [ ! -f "$PKG.tar.gz" ]; then
|
|
die "Cannot build RPM because $PKG.tar.gz does not exist"
|
|
fi
|
|
|
|
mkdir -p rpm rpm/BUILD rpm/SOURCES rpm/RPMS rpm/SRPMS
|
|
mkdir -p RPM
|
|
cd rpm
|
|
local topdir=`pwd`
|
|
|
|
# Build RPM package from the tarball.
|
|
rpmbuild -bb --clean $RPM_CONFIG_DIR/percona-toolkit.spec \
|
|
--quiet \
|
|
--define "_topdir $PWD" \
|
|
--define "_sourcedir $RELEASE_DIR" \
|
|
--define "version $VERSION" \
|
|
--define "release 1" > $tmpdir/rpmbuild 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
warn "rpmbuild has warnings; see $tmpdir/rpmbuild"
|
|
fi
|
|
|
|
if [ ! -f "RPMS/noarch/$PKG-1.noarch.rpm" ]; then
|
|
die "RPMS/noarch/$PKG-1.noarch.rpm did not build"
|
|
fi
|
|
mv "RPMS/noarch/$PKG-1.noarch.rpm" $RELEASE_DIR/RPM
|
|
rm -rf $RELEASE_DIR/rpm
|
|
|
|
echo "OK"
|
|
}
|
|
|
|
build_deb() {
|
|
local deb_pkg="percona-toolkit_$VERSION-1_all.deb"
|
|
echo -n "Building $deb_pkg... "
|
|
|
|
cd $RELEASE_DIR
|
|
if [ ! -f "$PKG.tar.gz" ]; then
|
|
die "Cannot build RPM because $PKG.tar.gz does not exist"
|
|
fi
|
|
|
|
# Copy debian pkg files.
|
|
if [ ! -d "$RELEASE_DIR/$PKG/debian" ]; then
|
|
mkdir $RELEASE_DIR/$PKG/debian
|
|
else
|
|
rm -rf * $RELEASE_DIR/$PKG/debian
|
|
fi
|
|
cp $BRANCH/config/deb/* $RELEASE_DIR/$PKG/debian/
|
|
|
|
# Build Debian binary and source packages.
|
|
cd $RELEASE_DIR/$PKG
|
|
dpkg-buildpackage -us -uc >$tmpdir/dpkg-buildpackage 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
warn "dpkg-buildpackage has warnings; see $tmpdir/dpkg-buildpackage"
|
|
fi
|
|
|
|
rm -rf debian/ build-stamp >/dev/null
|
|
make distclean >/dev/null
|
|
cd $RELEASE_DIR
|
|
rm -rf *.changes >/dev/null
|
|
|
|
mkdir -p deb
|
|
mv percona-toolkit_* deb/
|
|
|
|
echo "OK"
|
|
}
|
|
|
|
# ############################################################################
|
|
# Script starts here
|
|
# ############################################################################
|
|
|
|
if [ $# -lt 2 ]; then
|
|
die "Usage: $0 VERSION RELEASE_NOTES"
|
|
fi
|
|
VERSION=$1
|
|
REL_NOTES=$2
|
|
|
|
if [ ! -f $REL_NOTES ]; then
|
|
die "$REL_NOTES does not exist"
|
|
fi
|
|
|
|
# My machine's language is not English. This affects DEB_DATE because
|
|
# date %a is language-sensitive. We want abbreviated day names in English.
|
|
# Setting LANG as such works for me; hopefully it works for you, too.
|
|
LANG='en_US.UTF-8'
|
|
|
|
SERIES=$(echo $VERSION | sed 's/\.[0-9][0-9]*$//')
|
|
YEAR=$(date -u +'%Y') # for updating copyright year
|
|
DATE=$(date -u +'%F') # for updating release date
|
|
DEB_DATE=$(date -u +'%a, %d %b %Y %T %z') # for updating deb/changelog
|
|
PKG="percona-toolkit-$VERSION" # what we're building
|
|
|
|
# mktemp -d doesn't work on Mac OS X, so we'll do it the old-fashioned way.
|
|
tmpdir="/tmp/build-percona-toolkit-$VERSION"
|
|
rm -rf $tmpdir >/dev/null 2>&1
|
|
mkdir $tmpdir
|
|
|
|
BETA=${BETA:-0}
|
|
if [ $BETA -eq 1 ]; then
|
|
UPDATE_DOCS=0
|
|
BUILD_RPM=0
|
|
BUILD_DEB=0
|
|
fi
|
|
|
|
# This script does not check that you've done pre-release tasks like running
|
|
# the test suite, updating Changelog entries, etc. You're responsible for
|
|
# that. These checks are for the sanity of package building.
|
|
CHECK=${CHECK:-1}
|
|
if [ $CHECK -eq 1 ]; then
|
|
check_branch
|
|
check_version
|
|
check_changelog
|
|
check_rel_notes
|
|
fi
|
|
|
|
# These items need to be updated automatically for each release.
|
|
UPDATE=${UPDATE:-1}
|
|
if [ $UPDATE -eq 1 ]; then
|
|
update_version
|
|
update_copyright_year
|
|
update_manifest
|
|
|
|
UPDATE_DOCS=${UPDATE_DOCS:-1}
|
|
if [ $UPDATE_DOCS -eq 1 ]; then
|
|
update_percona_toolkit_pod
|
|
update_changelog
|
|
update_rel_notes
|
|
update_user_docs
|
|
fi
|
|
fi
|
|
|
|
# Now that those ^ items are updated, you need to commit and push one more
|
|
# time before the release packages are built. This script can't do that
|
|
# because your branch could non-standard.
|
|
BUILD=${BUILD:-1}
|
|
if [ $BUILD -eq 1 ]; then
|
|
cat <<MSG
|
|
|
|
Branch verified and updated; ready to build $PKG,
|
|
but first you must:
|
|
|
|
1. git diff and review the changes (Changelog, percon-toolkit.pod, etc.)
|
|
2. git add . (from root dir of project)
|
|
3. git commit -m "Build $PKG"
|
|
4. git push origin <release-branch>
|
|
|
|
Press any key to continue... (or Ctrl-C to abort)
|
|
MSG
|
|
|
|
read
|
|
|
|
prep_release_dir
|
|
|
|
BUILD_TAR=${BUILD_TAR:-1}
|
|
if [ $BUILD_TAR -eq 1 ]; then
|
|
build_tar
|
|
fi
|
|
|
|
BUILD_RPM=${BUILD_RPM:-1}
|
|
if [ $BUILD_RPM -eq 1 ]; then
|
|
build_rpm
|
|
fi
|
|
|
|
BUILD_DEB=${BUILD_DEB:-1}
|
|
if [ $BUILD_DEB -eq 1 ]; then
|
|
build_deb
|
|
fi
|
|
|
|
if [ -d $RELEASE_DIR/$PKG ]; then
|
|
rm -rf $RELEASE_DIR/$PKG
|
|
fi
|
|
|
|
echo "Done building $PKG. Packages are in $RELEASE_DIR"
|
|
fi
|
|
|
|
exit $exit_status
|