#!/bin/bash
#
# A simple script to wrap the execution of a command so that it stores its
# output and return value into a file and then process it to later on.
#
# This is meant to be used in a makefile, specifically to allow for the output
# of a command to be stored in a file and added to the dist list, even if the
# command actually failed.
#
# For example, your makefile might include:
#
# my_target := lint
# my_target_output := $(OUT_DIR)/lint-output.txt
# my_target_retval := $(OUT_DIR)/lint-retval.txt
#
# $(my_target_output) $(my_target_retval): PRIVATE_MODULE := $(my_target)
# $(my_target_output) $(my_target_retval): PRIVATE_OUTPUT := $(my_target_output)
# $(my_target_output) $(my_target_retval): PRIVATE_RETVAL := $(my_target_retval)
# $(my_target_output) $(my_target_retval):
#         $(PATH)/wrapper.sh \
#           $(PRIVATE_MODULE) \
#           $(PRIVATE_OUTPUT) \
#           $(PRIVATE_RETVAL) \
#           wrap \
#           $(PATH)/run-list.sh $(LOCAL_PATH)/src
#
# $(my_target): PRIVATE_MODULE := $(my_target)
# $(my_target): PRIVATE_OUTPUT := $(my_target_output)
# $(my_target): PRIVATE_RETVAL := $(my_target_retval)
# $(my_target): $(my_target_output) $(my_target_retval)
#         $(PATH)/wrapper.sh \
#           $(PRIVATE_MODULE) \
#           $(PRIVATE_OUTPUT) \
#           $(PRIVATE_RETVAL) \
#           eval

set -euo pipefail

# Terminate with a fatal error.
function fatal() {
  echo "Fatal: $*"
  exit 113
}

function main() {
  local module="${1-}"; shift || fatal "missing argument: module"
  local output="${1-}"; shift || fatal "missing argument: output"
  local retval="${1-}"; shift || fatal "missing argument: retval"
  local action="${1-}"; shift || fatal "missing argument: action"
  # The rest of the arguments are the command to run.

  if [ "$action" = 'wrap' ]; then
    # Run the command specified by the rest of arguments ("$@") and save output
    # and return value.
    echo 0 >"${retval}"
    "$@" >"${output}" 2>&1 || echo "$?" >"${retval}"

    # Wrapping itself is always successful.
    return
  elif [ "$action" = 'eval' ]; then
    local result="$(cat "${retval}")"
    if [ "$result" = 0 ]; then
      # If successful only print the last few lines.
      tail -n 5 "$output" | sed -e "s/^/${module}: /"
    else
      # Print the entire output on failure.
      cat "$output" | sed -e "s/^/${module}: /"
    fi
    # Evaluating returns the stored return value.
    return "$result"
  else
    fatal "invalid action: $action"
  fi
}

main "$@"