#!/bin/sh
##########################################################
# Butterfly Control System #
##########################################################
# -------------- utility functions ----------------------
fail () {
cat <<EOF
ERROR: $1
Type '$0 -h' for usage information.
EOF
exit 1
}
error() {
echo "$1"
exit 1
}
warn() {
echo "$1"
exit 0
}
usage() {
cat <<EOF
Usage: $0 [options] <action>
where [options] include:
-h print this message and exit
-p <port> the port that the server will listen to
default: 8080
-i <interface> the host interface the server will bind to
default: 127.0.0.1
-w <path> path to the webapp
default: main/webapp
-m <memory> max memory heap size to use
default: 1024M
--debug enable JVM debugging (on port 8000)
--jmx enable JMX monitoring (for jconsole and jvisualvm)
and <action> is one of
build ..................... Build Butterfly
run ....................... Run Butterfly [default]
appengine_build ........... Build Butterfly webapp for Google App Engine
appengine_run ............. Run Butterfly webapp for Google App Engine in local server
appengine_upload .......... Upload Butterfly webapp to Google App Engine
test ...................... Run Butterfly tests
findbugs .................. Run Findbugs against Butterfly
pmd ....................... Run PMD against Butterfly
cpd ....................... Run Copy/Paste Detection against Butterfly
jslint .................... Run JSlint against Butterfly
whitespace <extension> .... Normalize whitespace in files with the given extension
clean ..................... Clean compiled classes
distclean ................. Remove all generated files
EOF
exit 1
}
add_option() {
OPTS="$OPTS $1"
}
load_configs() {
cat $1 | egrep "^[A-Z]" | sed 's/^\(.*\)$/export \1/' > .$1
. ./.$1
rm ./.$1
}
absolutize() {
case $1 in
/*) echo $1; ;;
*) echo `pwd`/$1; ;;
esac
}
check_macosx() {
if ! $DARWIN ; then
error "This action can only run on MacOSX"
fi
}
check_downloaders() {
CURL="`which curl 2> /dev/null`"
WGET="`which wget 2> /dev/null`"
if [ -z "$CURL" -a -z "$WGET" ]; then
error "We need either 'curl' or 'wget' present in PATH to download external dependencies."
fi
}
check_unzip() {
UNZIP="`which unzip 2> /dev/null`"
if [ -z "$UNZIP" ]; then
error "We need 'unzip' present in PATH to expand external dependencies."
fi
}
check_running() {
check_downloaders
URL="http://${SERVER_HOST}:${SERVER_PORT}/"
if [ "$CURL" ]; then
NOT_RUNNING=`curl -s $URL > /dev/null || echo not_running`
elif [ "$WGET" ]; then
NOT_RUNNING=`wget -q -O - $URL > /dev/null || echo not_running`
fi
}
get_revision() {
if [ -d ".svn" ]; then
INFO=`svn info`
elif [ -d ".git" ]; then
INFO=`git svn info`
else
error "cannot obtain revision, exiting!"
fi
REVISION=`echo $INFO | sed 's/.*Revision: /r/' | sed 's/ .*//'`
}
download() {
URL=$1
DEST=$2
check_downloaders
if [ "$CURL" ]; then
curl -L -o $DEST $URL || exit "Error while downloading $URL"
elif [ "$WGET" ]; then
wget -O $DEST $URL || error "Error while downloading $URL"
fi
}
tool_download() {
URL=$1
FILE=$2
DIR=$3
cd $TOOLS_DIR
if [ ! -f "$FILE" ]; then
download $URL $FILE
fi
if [ ! -d "$DIR" ]; then
if [ -z "`echo $FILE | sed 's@.*.tar.gz$@@' | sed 's@.*.tgz$@@'`" ]; then
tar xzf $FILE || error "Error while expanding $FILE"
fi
if [ -z "`echo $FILE | sed 's@.*.zip$@@'`" ]; then
check_unzip
$UNZIP -q $FILE || error "Error while expanding $FILE"
fi
fi
cd ..
}
# ----------------------------------------------------------------------------------------------
build_prepare() {
if [ ! -d $BUILD_DIR ]; then
mkdir $BUILD_DIR || error "Error while making directory $BUILD_DIR"
fi
}
dist_prepare() {
if [ ! -d $DIST_DIR ]; then
mkdir $DIST_DIR || error "Error while making directory $DIST_DIR"
fi
}
tools_prepare() {
if [ ! -d $TOOLS_DIR ]; then
mkdir $TOOLS_DIR || error "Error while making directory $TOOLS_DIR"
fi
}
appengine_prepare() {
if [ -z "$APPENGINE_HOME" ]; then
error "You have to have the APPENGINE_HOME environment variable set and pointing to the local installation of the Google AppEngine SDK."
elif [ ! -f "$APPENGINE_HOME/bin/appcfg.sh" ]; then
error "Environment variable APPENGINE_HOME is set to '$APPENGINE_HOME' which doesn't point to a valid Google App Engine SDK."
fi
APPENGINE="$APPENGINE_HOME/bin/appcfg.sh"
APPENGINE_LOCAL="$APPENGINE_HOME/bin/dev_appserver.sh"
ANT_PARAMS="$ANT_PARAMS -Dappengine.sdk.dir=$APPENGINE_HOME"
}
ant_prepare() {
tools_prepare
ANT_URL="http://archive.apache.org/dist/ant/binaries/apache-ant-1.8.1-bin.tar.gz"
ANT_FILE=`echo $ANT_URL | sed 's|.*/||'`
ANT_DIR="apache-ant-1.8.1"
ANT="`which ant 2> /dev/null`"
if [ -z "$ANT" ]; then
if [ -z "$ANT_HOME" ]; then
cd $TOOLS_DIR
if [ ! -f "$ANT_FILE" ]; then
download $ANT_URL $ANT_FILE
fi
if [ ! -d "$ANT_DIR" ]; then
tar xzf $ANT_FILE -C . || error "Error while expanding $ANT_FILE"
fi
export ANT_HOME="`pwd`/$ANT_DIR"
if $CYGWIN ; then
export ANT_HOME=`cygpath --unix "$ANT_HOME"`
fi
cd ..
fi
ANT="$ANT_HOME/bin/ant"
fi
get_revision
}
findbugs_prepare() {
tools_prepare
FINDBUGS_URL="http://downloads.sourceforge.net/project/findbugs/findbugs/1.3.9/findbugs-1.3.9.tar.gz"
FINDBUGS_FILE=`echo $FINDBUGS_URL | sed 's|.*/||'`
FINDBUGS_DIR="findbugs-1.3.9"
tool_download $FINDBUGS_URL $FINDBUGS_FILE $FINDBUGS_DIR
}
pmd_prepare() {
tools_prepare
PMD_URL="http://downloads.sourceforge.net/project/pmd/pmd/4.2.5/pmd-bin-4.2.5.zip"
PMD_FILE="pmd-bin-4.2.5.zip"
PMD_DIR="pmd-4.2.5"
tool_download $PMD_URL $PMD_FILE $PMD_DIR
}
jslint_prepare() {
tools_prepare
JSLINT_URL="http://jslint4java.googlecode.com/files/jslint4java-1.3.3-dist.zip"
JSLINT_FILE="jslint4java-1.3.3-dist.zip"
JSLINT_DIR="jslint4java-1.3.3"
tool_download $JSLINT_URL $JSLINT_FILE $JSLINT_DIR
}
# ----------------------------------------------------------------------------------------------
ant() {
ant_prepare
#export ANT_OPTS="-Xmx1024M"
"$ANT" -f build.xml $ANT_PARAMS -Drevision="$REVISION" $1 || error "Error while running ant task '$1'"
}
# ----------------------------------------------------------------------------------------------
test() {
ant build_tests
echo ""
CLASSPATH="$TEST_DIR/classes${SEP}$WEBAPP/WEB-INF/classes${SEP}$SERVER_CLASSES_DIR${SEP}$TEST_DIR/lib/*${SEP}$SERVER_LIB_DIR/*${SEP}$WEBAPP/WEB-INF/lib/*"
if [ -z "$1" ]; then
TESTS="-excludegroups broken $TEST_DIR/conf/tests.xml"
else
TESTS="-testclass $1"
fi
RUN_CMD="$JAVA -cp $CLASSPATH $OPTS org.testng.TestNG -d $BUILD_DIR/tests -listener org.testng.reporters.DotTestListener $TESTS"
#echo "$RUN_CMD"
#echo ""
$RUN_CMD || error "Failed passing tests"
}
run() {
FORK=$1
if [ ! -d $SERVER_CLASSES_DIR ]; then
IS_JAR=`ls $SERVER_LIB_DIR | grep butterfly`
if [ -z "$IS_JAR" ]; then
ant build
echo ""
fi
fi
check_running
if [ -z "$NOT_RUNNING" ]; then
warn "Butterfly is already running."
fi
if [ -d $SERVER_CLASSES_DIR ]; then
add_option "-Dserver.autoreload=true"
add_option "-Dbutterfly.autoreload=true"
fi
CLASSPATH="$SERVER_CLASSES_DIR${SEP}$SERVER_LIB_DIR/*"
RUN_CMD="$JAVA -cp $CLASSPATH $OPTS edu.mit.simile.butterfly.ButterflyServer"
#echo "$RUN_CMD"
#echo ""
echo "Starting Butterfly at 'http://${SERVER_HOST}:${SERVER_PORT}/'"
echo ""
if [ -z "$FORK" ]; then
exec $RUN_CMD
else
$RUN_CMD &
SERVER_PID="$!"
fi
}
appengine_build() {
appengine_prepare
ANT_PARAMS="-Dappengine.sdk.dir=${APPENGINE_HOME}"
if [ "$1" ]; then
ANT_PARAMS="$ANT_PARAMS -Dappengine.version=$1"
fi
ant prepare_webapp_appengine
}
appengine_upload() {
appengine_build $1
"$APPENGINE" update "$BUILD_DIR/appengine"
}
appengine_run() {
appengine_build $1
"$APPENGINE_LOCAL" "$BUILD_DIR/appengine"
}
findbugs() {
findbugs_prepare
ANT_PARAMS="-Dfindbugs.dir=${TOOLS_DIR}/${FINDBUGS_DIR}"
ant findbugs
open "$BUILD_DIR/reports/findbugs.html"
}
pmd() {
pmd_prepare
ANT_PARAMS="-Dpmd.dir=${TOOLS_DIR}/${PMD_DIR}"
ant pmd
open "$BUILD_DIR/reports/pmd.html"
}
cpd() {
pmd_prepare
ANT_PARAMS="-Dpmd.dir=${TOOLS_DIR}/${PMD_DIR}"
ant cpd
open "$BUILD_DIR/reports/cpd.txt"
}
jslint() {
jslint_prepare
ANT_PARAMS="-Djslint.dir=${TOOLS_DIR}/${JSLINT_DIR}"
ant jslint
open "$BUILD_DIR/reports/jslint.txt"
}
whitespace() {
[ $# -gt 0 ] || usage
for i in `find . -name *.$1`; do
# expand tabs to spaces
expand -t 4 < $i > $i.1
# convert DOS to UNIX newlines
tr -d '\r' < $i.1 > $i.2
rm $i $i.1
mv $i.2 $i
done
}
# -------------------------- script -----------------------------
# ----- Normalize the current directory -------------------------
cd `dirname $0`
# ----- Default values ------------------------------------------
OPTS=""
# ---- OS-specific support --------------------------------------
SYSTEM=`uname`
CYGWIN=false
DARWIN=false
case "$SYSTEM" in
CYGWIN*) CYGWIN=true ;;
Darwin*) DARWIN=true ;;
esac
SEP=":"
if $CYGWIN ; then
SEP=";"
fi
# ----- Load configurations -------------------------------------
load_configs butterfly.ini
# ----- Make sure there is an appropriate java environment is available -------------
if $DARWIN ; then
if [ -z "$JAVA_HOME" ]; then
# Mac OS X defaults to Java 5. So update JAVA_HOME unless the user manually set it.
export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home"
fi
fi
JAVA="`which java 2> /dev/null`"
if [ -z "$JAVA" ]; then
if [ "$JAVA_HOME" ]; then
JAVA="$JAVA_HOME/bin/java"
if [ ! -f "$JAVA" ] ; then
error "Could not find the 'java' executable at '$JAVA', are you sure your JAVA_HOME environment variable is pointing to a proper java installation?"
fi
else
error "The 'java' command should be in your path or the 'JAVA_HOME' environment variable should be set"
fi
fi
JAVA_VERSION=`$JAVA -version 2>&1 | grep version | cut -d ' ' -f 3 | egrep ^\"1\.6`
if [ -z "$JAVA_VERSION" ]; then
error "Butterfly requires Java version 6 or later. If you have multiple versions of Java installed, please set JAVA_HOME to the correct version."
fi
# ----- Parse the command line args ------------------------------------------
while [ $# -ne 0 ] ; do
case "$1" in
-h) usage;;
-p) shift; SERVER_PORT="$1"; shift; continue;;
-i) shift; SERVER_HOST="$1"; shift; continue;;
-w) shift; WEBAPP="$1"; shift; continue;;
-m) shift; SERVER_MEMORY="$1"; shift; continue;;
--debug) shift; add_option '-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n'; continue;;
--jmx) shift; add_option '-Dcom.sun.management.jmxremote'; continue;;
-*) fail "Invalid option: $1";;
*) break;;
esac
done
if [ $# -ne 0 ]; then
ACTION=$1; shift
fi
if [ -z "$ACTION" ]; then
ACTION="run"
fi
# ----- Verify and Set Required Environment Variables -------------------------
if [ -z "$JAVA_OPTIONS" ]; then
JAVA_OPTIONS=""
fi
add_option "$JAVA_OPTIONS"
if [ -z "$SERVER_MEMORY" ]; then
SERVER_MEMORY="1024M"
fi
add_option "-Xms256M -Xmx$SERVER_MEMORY -Dserver.memory=$SERVER_MEMORY"
if [ -z "$SERVER_PORT" ]; then
SERVER_PORT="8080"
fi
add_option "-Dserver.port=$SERVER_PORT"
if [ -z "$SERVER_HOST" ]; then
SERVER_HOST="127.0.0.1"
fi
add_option "-Dserver.host=$SERVER_HOST"
if [ -z "$SERVER_CLASSES_DIR" ]; then
SERVER_CLASSES_DIR="server/classes"
fi
if [ -z "$SERVER_LIB_DIR" ]; then
SERVER_LIB_DIR="server/lib"
fi
if [ -z "$WEBAPP" ]; then
WEBAPP="main/webapp"
fi
add_option "-Dserver.webapp=$WEBAPP"
if [ -z "$TEST_DIR" ]; then
TEST_DIR="main/tests"
fi
if [ -z "$BUILD_DIR" ]; then
BUILD_DIR="build"
fi
if [ -z "$TOOLS_DIR" ]; then
TOOLS_DIR="tools"
fi
if [ -z "$DIST_DIR" ]; then
DIST_DIR="dist"
fi
# ----------- Butterfly Properties -----------------------------------
if [ -z "$BUTTERFLY_WIRINGS" ]; then
BUTTERFLY_WIRINGS="`absolutize modules.properties`"
fi
add_option "-Dbutterfly.modules.wirings=$BUTTERFLY_WIRINGS";
if [ -z "$BUTTERFLY_MODULES_PATH" ]; then
BUTTERFLY_MODULES_PATH="`absolutize modules`"
fi
add_option "-Dbutterfly.modules.path=$BUTTERFLY_MODULES_PATH";
if [ "$BUTTERFLY_PROPERTIES" ]; then
add_option "-Dbutterfly.properties=`absolutize $BUTTERFLY_PROPERTIES`";
fi
if [ "$BUTTERFLY_DEFAULT_ZONE" ]; then
add_option "-Dbutterfly.default.zone=$BUTTERFLY_DEFAULT_ZONE";
fi
# ----- Respond to the action given --------------------------------------------
case "$ACTION" in
build) build_prepare; ant jar;;
clean) ant clean;;
whitespace) whitespace $1;;
distclean) ant distclean;;
test) test $1;;
tests) test $1;;
findbugs) findbugs;;
pmd) pmd;;
cpd) cpd;;
jslint) jslint;;
appengine_build) appengine_build $1;;
appengine_run) appengine_run $1;;
appengine_upload) appengine_upload $1;;
run) run;;
*) usage; ;;
esac