#!/bin/sh -e

usage() {
    echo "usage: $0 [options] [cmd...]
options:
    -h,--help                   Show this help
    -r,--retries=RETRIES        How many retries to do on command failure after
                                the initial try. Set -1 for infinite retries.
                                Defaults to 3.
    -s,--sleep=SLEEP            How many seconds to sleep between retries.
                                Defaults to 3 seconds.
    -e,--exponential[=FACTOR]   Enable simple exponential back-off algorithm.
                                Disabled by default, factor defaults to 2
                                (binary exponential back-off).
    "
}

# parse arguments
opts=$(getopt \
    --options +h,r:,s:,e:: \
    --longoptions help,retries:,sleep:,exponential:: \
    --name "$(basename "$0")" -- "$@") || { usage ; exit 1; }

eval set -- "$opts"

while [ $# -gt 0 ]; do
  case "$1" in
    -h | --help        ) usage; exit 0 ;;
    -r | --retries     ) retries=$2; shift 2 ;;
    -s | --sleep       ) sleep=$2; shift 2 ;;
    -e | --exponential ) exponential=${2:-2}; shift 2 ;;
    --                 ) shift; break ;;
    *                  ) break ;;
  esac
done

retries="${retries:-3}"
sleep="${sleep:-3}"

ret=0
retries_msg=""
while true; do
    ret=0
    "$@" && exit
    ret=$?
    if [ "$retries" = 0 ]; then
        break
    elif [ "$retries" != -1 ]; then
        retries_msg="up to $retries more times "
        retries=$((retries-1))
    fi
    echo "Retrying ${retries_msg}after sleeping ${sleep}s …" >&2
    sleep "$sleep"
    [ -n "$exponential" ] && sleep=$((sleep*exponential))
done

exit "$ret"
