#!/bin/bash

# Cronic v2 - cron job report wrapper
# Copyright 2007 Chuck Houpt
# Documentation at http://habilis.net/cronic/
# In brief:
#   Cronic is a small shim shell script for wrapping cron jobs so that cron
#   only sends email when an error has occurred. Cronic defines an error as
#   any non-trace error output or a non-zero result code. Cronic filters
#   Bash execution traces (or anything matching PS4) from the error output,
#   so jobs can be run with execution tracing to aid forensic
#   debugging. Cronic has no options, it simply executes its arguments.
# Extended by Michael Ernst to add --expected-status, --permit-stderr, and --duplicate-stderr flags.

# Exit if a command exits with a non-zero status, and treat unset variables
# as an error.
set -eu

OUT=/tmp/cronic.out.$$
ERR=/tmp/cronic.err.$$
TRACE=/tmp/cronic.trace.$$

EXPECTED=0
if [ "$1" == "--expected-status" ]; then
  shift
  EXPECTED=$1
  shift
fi
PERMITSTDERR=0
if [ "$1" == "--permit-stderr" ]; then
  shift
  PERMITSTDERR=1
fi
DUPLICATE_STDERR=0
if [ "$1" == "--duplicate-stderr" ]; then
  shift
  DUPLICATE_STDERR=1
fi

set +e
"$@" > $OUT 2> $TRACE
RESULT=$?
set -e

PATTERN="^${PS4:0:1}\\+${PS4:1}"
if grep -q "$PATTERN" $TRACE; then
  grep -v "$PATTERN" $TRACE > $ERR
else
  ERR=$TRACE
fi

if [ $RESULT -ne "$EXPECTED" ] || { [ $PERMITSTDERR -eq 0 ] && [ -s "$ERR" ]; }; then
  echo "Cronic detected failure or error output for the command:"
  echo "$@"
  echo
  if [[ $EXPECTED -eq 0 ]]; then
    echo "RESULT CODE: $RESULT  (0 means success)"
  else
    echo "RESULT CODE: $RESULT  (expected: $EXPECTED)"
  fi
  echo
  echo "ERROR OUTPUT:"
  cat "$ERR"
  echo
  echo "STANDARD OUTPUT:"
  cat "$OUT"
  if [ $TRACE != $ERR ]; then
    echo
    echo "TRACE-ERROR OUTPUT:"
    cat "$TRACE"
  fi
  if [ $DUPLICATE_STDERR -eq 1 ]; then
    echo
    echo "ERROR OUTPUT:"
    cat "$ERR"
  fi
fi

rm -f "$OUT"
if [ ! $ERR == /dev/null ]; then
  rm -f "$ERR"
fi
rm -f "$TRACE"
exit $RESULT
