#!/bin/bash
# Directory of uncompiled source files starting from build script's path without leading and
# trailing slashes.
source_directory="src"
# Target directory for compiled files starting from build script's path without leading and
# trailing slashes.
build_directory="build"
# Compiler executor for Coffeescript files. Check build task for execution details if you use
# something different from Coffeescript.
compiler=coffee
# Executor for Node applications. Used to run tests and start servers. Check these tasks for
# execution details if you use something different from Node.
application_launcher=node
# Relative path from build directory; start-server uses something like
# `$application_launcher "$build_directory/$server_start_script"` to start the server.
# Uncomment to ignore start-server task.
server_start_script="run-server.js"
name=$(basename "$0")
if [[ "$#" == "0" ]]; then
echo "$name: Missing task list"
echo
echo "Usage: $name [ task1 ] [ task2 ] [ task3 ] [ ... ]"
echo
echo "Tasks:"
echo " build: Build project and tests."
echo
echo " test: Build project and run all tests."
echo " Equivalent to \"$name build run-tests\"."
echo " run-tests: Run all tests."
echo
echo " server: Stop running server (if existing), build project and start server."
echo " Equivalent to \"$name stop-server build start-server\"."
echo " restart-server: Stop running server (if existing) and start server."
echo " Equivalent to \"$name stop-server start-server\"."
echo " start-server: Start server."
echo " stop-server: Stop running server (if existing)."
echo
echo " watch: Start infinite loop triggering succeeding tasks whenever a file changes"
echo " in project directory. Use only once."
echo " dev: Build everything, restart server, run tests and repeat whenever a file"
echo " changes. Equivalent to \"$name test watch test\"."
exit 1
fi
# cd to script's directory for relative links
cd $(cd $(dirname $0); pwd -P)
# task list to be executed
tasks=("${@:1}")
# ensure that needed programs are installed
for program in $compiler $application_launcher; do
hash $program 2>/dev/null || {
echo >&2 "Please install required $program. Aborting."; exit 1;
}
done
notify() {
# platform-dependent function to send simple desktop notifications
local message=$1 # the message to be sent
local message_type=$2 # "error" || "success" || undefined
# linux: notify-send
if hash "notify-send" 2> /dev/null; then
local icon="face-plain"
if [[ "$message_type" == "error" ]]; then
icon="error"
elif [[ "$message_type" == "success" ]]; then
icon="face-smile-big"
fi
notify-send -u low -t 500 -i "$icon" "$message"
fi
}
build() {
echo "Build project..."
changes=( "$(rsync -av "$source_directory/" "$build_directory")" )
for filepath in $changes; do
if [[ $filepath == *.coffee ]]; then
$compiler -b --compile "$build_directory/$filepath"
fi
done
}
run_tests() {
echo "Execute tests..."
$application_launcher $build_directory/test/precompiler.spec.js
if [[ $? > 0 ]]; then
notify "One or more tests failed!" "error"
else
notify "All tests passed." "success"
fi
}
start_server() {
if [ -n "$server_start_script" ]; then
echo "Start server..."
$application_launcher "$build_directory/$server_start_script" &
echo $! > .serverpid
fi
}
stop_server() {
if [ -f ".serverpid" ]; then
local server_pid=$(head -n 1 .serverpid)
rm .serverpid
if [[ $server_pid > 0 ]]; then
echo "Stop server..."
kill $server_pid
server_pid=0
fi
fi
}
watch() {
echo "Waiting for file changes..."
tasks=("${tasks[@]}" "watch" "${tasks[@]}")
inotifywait -rqe close_write,moved_to,create "$source_directory"
}
process_tasks() {
while [[ ${#tasks[@]} > 0 ]]; do
local task=${tasks[0]}
unset tasks[0]
tasks=("${tasks[@]}")
case "$task" in
'build')
build
;;
'test')
build
run_tests
;;
'run-tests')
run_tests
;;
'server')
stop_server
build
start_server
;;
'restart-server')
stop_server
start_server
;;
'start-server')
start_server
;;
'stop-server')
stop_server
;;
'watch')
watch
;;
'dev')
./$0 server run-tests watch server run-tests
exit
;;
*)
echo "WARNING: Unknown task $task. Skip and continue..."
;;
esac
done
}
process_tasks