#!/bin/bash # shoreman is an implementation of the Procfile format. Inspired by # the original [foreman](ddollar.github.com/foreman/) tool for ruby, # as well as [norman](github.com/josh/norman) for node.js.

# Make sure that any errors cause the script to exit immediately. set -e

# ## Usage

# Usage message that is displayed when ‘–help` is given as an argument. #/ Usage: shoreman [<procfile>] #/ Run Procfiles using shell. #/ #/ The shoreman script reads commands from <procfile> and starts up the #/ processes that it describes.

# Stolen from shocco. This formats the usage message above by grepping this # file for lines starting with ‘#/`. expr – “$*” : “.*–help” >/dev/null && {

grep '^#/' <"$0" | cut -c4-
exit 0

}

# ## Logging

# For logging we want to prefix each entry with the current time, as well # as the process name. This takes one argument, the name of the process, and # then reads data from stdin, formats it, and sends it to stdout. log() {

while read data
do
  echo "$(date +"%H:%M:%S") $1\t| $data"
done

}

# ## Running commands

# When a process is started, we want to keep track of its pid so we can # ‘kill` it when the parent process receives a signal, and so we can `wait` # for it to finish before exiting the parent process. store_pid() {

pids=("${pids[@]}" "$1")

}

# This starts a command asynchronously and stores its pid in a list for use # later on in the script. start_command() {

sh -c "$1" &
pid="$!"
store_pid "$pid"

}

# ## Reading the .env file if there is one

# The .env file needs to be a list of assignments like in a shell script. # Only lines containing an equal sign are read, which means you can add comments. # Preferably shell-style comments so that your editor print them like shell scripts.

ENV_FILE=${2:-‘.env’} if [ -f $ENV_FILE ]; then

while read line || [ -n "$line" ]; do
  if [[ "$line" == *=* ]]; then
    eval "export $line"
  fi
done < "$ENV_FILE"

fi

# ## Reading the Procfile

# The Procfile needs to be parsed to extract the process names and commands. # The file is given on stdin, see the ‘<` at the end of this while loop. PROCFILE=${1:-’Procfile’} while read line || [ -n “$line” ]; do

name=${line%%:*}
command=${line#*: }
start_command "$command"
echo "'${command}' started with pid ${pid}" | log "${name}.1"

done < “$PROCFILE”

# ## Cleanup

# When a ‘SIGINT`, `SIGTERM` or `EXIT` is received, this action is run, killing the # child processes. The sleep stops STDOUT from pouring over the prompt, it # should probably go at some point. onexit() {

echo SIGINT received
echo sending SIGTERM to all processes
kill ${pids[*]} &>/dev/null
sleep 1

} trap onexit SIGINT SIGTERM EXIT

# Wait for the children to finish executing before exiting. wait