blob: 4aedeaeb38307cba3de9a630680e644bffa25090 [file] [log] [blame]
#!/bin/bash
#
# Copyright 2011 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: sligocki@google.com (Shawn Ligocki)
#
# Common shell utils.
# Usage: kill_prev PORT
# Kill previous processes listening to PORT.
function kill_prev() {
echo -n "Killing anything that listens on 0.0.0.0:$1... "
local pids=$(lsof -w -n -i "tcp:$1" -s TCP:LISTEN -Fp | sed "s/^p//" )
if [[ "${pids}" == "" ]]; then
echo "no processes found";
else
kill -9 ${pids}
echo "done"
fi
}
# Usage: wait_cmd CMD [ARG ...]
# Wait for a CMD to succeed. Tries it 10 times every 0.1 sec.
# That maxes to 1 second if CMD terminates instantly.
function wait_cmd() {
for i in $(seq 10); do
if eval "$@"; then
return 0
fi
sleep 0.1
done
eval "$@"
}
# Usage: wait_cmd_with_timeout TIMEOUT_SECS CMD [ARG ...]
# Waits until CMD succeed or TIMEOUT_SECS passes, printing progress dots.
# Returns exit code of CMD. It works with CMD which does not terminate
# immediately.
function wait_cmd_with_timeout() {
# Bash magic variable which is increased every second. Note that assignment
# does not reset timer, only counter, i.e. it's possible that it will become 1
# earlier than after 1s.
SECONDS=0
while [[ "$SECONDS" -le "$1" ]]; do # -le because of measurement error.
if eval "${@:2}"; then
return 0
fi
sleep 0.1
echo -n .
done
eval "${@:2}"
}
GIT_VERSION=2.0.4
GIT_SHA256SUM=dd9df02b7dcc75f9777c4f802c6b8562180385ddde4e3b8479e079f99cd1d1c9
WGET_VERSION=1.12
WGET_SHA256SUM=7578ed0974e12caa71120581fa3962ee5a69f7175ddc3d6a6db0ecdcba65b572
MEMCACHED_VERSION=1.4.20
MEMCACHED_SHA256SUM=25d121408eed0b1522308ff3520819b130f04ba0554c68a673af23a915a54018
PYTHON_VERSION=2.7.8
PYTHON_SHA256SUM=74d70b914da4487aa1d97222b29e9554d042f825f26cb2b93abd20fdda56b557
REDIS_VERSION=3.2.4
REDIS_SHA256SUM=2ad042c5a6c508223adeb9c91c6b1ae091394b4026f73997281e28914c9369f1
GIT_SRC_URL=https://kernel.org/pub/software/scm/git/git-$GIT_VERSION.tar.gz
WGET_SRC_URL=https://ftp.gnu.org/gnu/wget/wget-$WGET_VERSION.tar.gz
# This is available on https, but CentOS 6's wget doesn't like the cert.
MEMCACHED_SRC_URL=http://www.memcached.org/files/memcached-$MEMCACHED_VERSION.tar.gz
PYTHON_SRC_URL=https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz
REDIS_SRC_URL=http://download.redis.io/releases/redis-$REDIS_VERSION.tar.gz
# Usage: install_from_src [package] [...]
# For all supplied package names, downloads and installs from source.
function install_from_src() {
local pkg
for pkg in "$@"; do
if [ -e "/usr/local/bin/$pkg" ]; then
echo "$pkg already installed, will not re-install"
continue
fi
case "$pkg" in
git) [ "$(lsb_release -is)" = "CentOS" ] && yum -y install curl-devel;
install_src_tarball $GIT_SRC_URL $GIT_SHA256SUM ;;
memcached) install_src_tarball $MEMCACHED_SRC_URL $MEMCACHED_SHA256SUM ;;
python2.7)
install_src_tarball $PYTHON_SRC_URL $PYTHON_SHA256SUM altinstall
# On Centos5, yum needs /usr/bin/python to be 2.4 but gclient needs
# python on the path to be 2.6 or later.
if [ "$(lsb_release -is)" = "CentOS" ] && \
version_compare "$(lsb_release -rs)" -lt 6; then
for dir in $HOME ~$SUDO_USER; do
mkdir -p $dir/bin && ln -sf /usr/local/bin/python2.7 $dir/bin/python
done
fi ;;
wget) install_src_tarball $WGET_SRC_URL $WGET_SHA256SUM ;;
redis-server) install_src_tarball $REDIS_SRC_URL $REDIS_SHA256SUM ;;
*) echo "Internal error: Unknown source package: $pkg" >&2; return 1 ;;
esac
done
}
# Usage: install_src_tarball <tarball_url> [install_target]
# Downloads the supplied tarball, builds and installs the contents.
# If install_target is supplied it will be used instead of "make install".
function install_src_tarball() {
if [ $# -lt 2 -o $# -gt 3 ]; then
echo "Usage: install_src_tarball <tarball> <sha256sum> [install_target]" >&2
exit 1
fi
local url="$1"
local expected_256sum="$2"
local install_target="${3:-install}"
local filename="$(basename "$url")"
local dirname="$(basename "$filename" .tar.gz)"
dirname="$(basename "$dirname" .tgz)"
local tmpdir="$(mktemp -d)"
pushd "$tmpdir"
# CentOS 5 can't fetch from the git repo because it has an ancient OpenSSL,
# so if a file has been scp'd manually, use it.
if [ -e "$HOME/$filename" ]; then
filename="$HOME/$filename"
else
wget "$url"
fi
local actual_256sum="$(sha256sum "$filename" | cut -d ' ' -f 1)"
if [ "$actual_256sum" != "$expected_256sum" ]; then
echo "sha256sum mismatch on $filename." >&2
echo "Expected $expected_256sum got $actual_256sum" >&2
exit 1
fi
# There's no error handling here because we ought to be running under set -e.
tar -xf "$filename"
cd "$dirname"
if [ -e ./configure ]; then
./configure
fi
make
echo "Installing $dirname"
sudo make $install_target
popd
rm -rf "$tmpdir"
}
# Usage: run_with_log [--verbose] <logfile> CMD [ARG ...]
# Runs CMD, writing its output to the supplied logfile. Normally silent
# except on failure, but will tee the output if --verbose is supplied.
function run_with_log() {
local verbose=
if [ "$1" = "--verbose" ]; then
verbose=1
shift
fi
local log_filename="$1"
mkdir -p "$(dirname "$log_filename")"
shift
local start_msg="[$(date '+%k:%M:%S')] $@"
# echo what we're about to do to stdout, including log file location.
echo "$start_msg >> $log_filename"
# Now write the same thing to the log.
echo "$start_msg" >> "$log_filename"
local rc=0
if [ -n "$verbose" ]; then
"$@" 2>&1 | tee -a "$log_filename"
rc=${PIPESTATUS[0]}
else
"$@" >> "$log_filename" 2>&1 || { rc=$?; true; }
fi
echo "[$(date '+%k:%M:%S')] Completed with exit status $rc" >> "$log_filename"
if [ $rc -ne 0 ]; then
echo
echo "End of $log_filename:"
if [ -n "${TRAVIS:-}" ]; then
# Travis has a 4MB total log output limit. -c 3000 is ~3MB.
tail -c 3000 "$log_filename"
else
tail -n 20 "$log_filename"
fi
fi
return $rc
}
# Compare version numbers in dotted notation.
# Usage: version_compare <version_a> <comparator> <version_b>
# For instance:
# if version_compare $version -lt 4.2; then echo "Too old!"; fi
#
function version_compare() {
if [ $# -ne 3 ]; then
echo "Usage: version_compare <version_a> <comparator> <version_b>" >&2
exit 1
fi
local a=$1
local comparator=$2
local b=$3
if [[ "$a" == *[^.0-9]* ]]; then
echo "Non-numeric version: $a" >&2
exit 1
fi
if [[ "$b" == *[^.0-9]* ]]; then
echo "Non-numeric version: $b" >&2
exit 1
fi
# The computed difference. 0 means a == b, -1 means a < b, 1 means a > b.
local difference=0
while [ $difference -eq 0 ]; do
if [ -z "$a" -a -z "$b" ]; then
break
elif [ -z "$a" ]; then
# a="" and b != "", therefore a < b
difference=-1
break
elif [ -z "$b" ]; then
# a != "" and b="", therefore a > b
difference=1
break
fi
# $a is N[.N.N]. Extract the first N from the beginning into $a_tok
local a_tok="${a%%.*}"
# Make $a any remaining N.N.
a="${a#*.}"
[ "$a" = "$a_tok" ] && a="" # Happens when there are no dots in $a
# Same for $b
local b_tok="${b%%.*}"
b="${b#*.}"
[ "$b" = "$b_tok" ] && b=""
# Now do the integer comparison between a and b.
if [ "$a_tok" -lt "$b_tok" ]; then
difference=-1
elif [ "$b_tok" -gt "$b_tok" ]; then
difference=1
fi
done
# Now do the actual comparison. We use the supplied comparator (say -le) to
# compare the computed difference with zero. This will return the expected
# result.
[ "$difference" "$comparator" 0 ]
}