Created
February 20, 2014 15:06
-
-
Save jjoos/9115718 to your computer and use it in GitHub Desktop.
[Foreman](https://github.com/ddollar/foreman) isn't supported anymore and there is a really annoying bug. When a process crashes not all other processes get killed properly. Since [foreman](https://github.com/ddollar/foreman) doesn't do too much, @Eamon rewrote it in bash. This is a rewrite inspired by his implementation. This script doesn't bre…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# default values | |
env_file_location=".env" | |
procfile_location="Procfile" | |
# possibly overwrites $env_file_location | |
read_command_line_options() { | |
# read the options | |
TEMP=`getopt e:h $*` | |
eval set -- "$TEMP" | |
# extract options and their arguments into variables. | |
while true ; do | |
case "$1" in | |
-e|--env) | |
case "$2" in | |
"") shift 2 ;; | |
*) env_file_location=$2 ; shift 2 ;; | |
esac ;; | |
--) shift ; break ;; | |
*) echo "Internal error!" ; exit 1 ;; | |
esac | |
done | |
if [[ $1 != '' ]]; then procfile_location="$1"; fi | |
} | |
export_key_values_from_env_file() { | |
# set -a make sure that all asignments are exported automatically | |
set -a | |
source $env_file_location | |
set +a | |
} | |
# sets $longest_name, $names and $commands | |
read_procfile() { | |
pattern='([^:/]+)(/.*/)?:(.*)' | |
counter=0 | |
longest_name=0 | |
while read line | |
do | |
if [[ $line =~ $pattern ]]; then | |
names[$counter]=${BASH_REMATCH[1]} | |
# accept input for the sed s command in the form /<regex>/replacement/ | |
# you should use double escapes in these patterns, keep the output if no | |
# pattern is provided. | |
if [[ ${BASH_REMATCH[2]} == '' ]]; then | |
replacements[$counter]='/(.*)/$1/'; | |
else | |
replacements[$counter]=${BASH_REMATCH[2]} | |
fi | |
commands[$counter]=${BASH_REMATCH[3]} | |
if (( "${#names[counter]}" > "$longest_name" )); then | |
longest_name=${#names[counter]} | |
fi | |
counter=$(( counter + 1 )) | |
fi | |
done < $procfile_location | |
} | |
# called when an exit signal is trapped, kills the jobs in the current group | |
onexit() { | |
printf "Shutting down ...\n" | |
kill -SIGINT $(jobs) &> /dev/null | |
sleep 2 | |
kill -SIGTERM $(jobs) &> /dev/null | |
sleep 2 | |
kill -SIGKILL 0 | |
} | |
# returs a function that pipes the jobs output and adds names and colours | |
format_output() { | |
declare -a colors=('1;31' '32' '36' '1;32' '1;33' '1;34' '1;35' '1;36' '35' | |
'31' '1;30' '34' '33') | |
# calculate how much whitespace should be added to align job output. | |
whitespace_length=$(( $longest_name - ${#names[counter]} )) | |
whitespace=`perl -e "print ' ' x $whitespace_length;"` | |
# Underline job names of error output | |
if [[ $1 == 'stderr' ]]; then error_modifier='4;'; fi | |
prefix=`echo -e "\e[$error_modifier${colors[counter]}m${names[counter]}\e[24m$whitespace| \e[0m"` | |
sed -u -e "s${replacements[counter]}g" -e "s/^/$prefix/" | |
} | |
read_command_line_options "$@" | |
export_key_values_from_env_file | |
read_procfile | |
# trap all exit signals to the onexit function | |
trap onexit SIGINT SIGTERM EXIT INT QUIT TERM | |
# loop through all process names | |
for counter in "${!names[@]}"; do | |
# execute the command and pipe the output through the formatter | |
{ | |
{ | |
eval "${commands[counter]}" || kill $$; | |
} 2>&1 1>&3 | format_output 'stderr' >&2; # stderr=>stdout stdin=>fd3 and stdout=>stderr | |
} 3>&1 | format_output 'stdout' & # fd3>stdout | |
# wait a miniscule amount of time (mitigating race conditions) | |
sleep 0.02 | |
done | |
# wait for all the jobs to quit | |
wait |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for sharing this! Ultimately this one didn't work b/c OS X sed does not support the
-u
option. I chose to use Shoreman, because that one just worked, but this put me on the path. Thanks!