1#!/bin/bash
2#
3# A simple script to wrap the execution of a command so that it stores its
4# output and return value into a file and then process it to later on.
5#
6# This is meant to be used in a makefile, specifically to allow for the output
7# of a command to be stored in a file and added to the dist list, even if the
8# command actually failed.
9#
10# For example, your makefile might include:
11#
12# my_target := lint
13# my_target_output := $(OUT_DIR)/lint-output.txt
14# my_target_retval := $(OUT_DIR)/lint-retval.txt
15#
16# $(my_target_output) $(my_target_retval): PRIVATE_MODULE := $(my_target)
17# $(my_target_output) $(my_target_retval): PRIVATE_OUTPUT := $(my_target_output)
18# $(my_target_output) $(my_target_retval): PRIVATE_RETVAL := $(my_target_retval)
19# $(my_target_output) $(my_target_retval):
20#         $(PATH)/wrapper.sh \
21#           $(PRIVATE_MODULE) \
22#           $(PRIVATE_OUTPUT) \
23#           $(PRIVATE_RETVAL) \
24#           wrap \
25#           $(PATH)/run-list.sh $(LOCAL_PATH)/src
26#
27# $(my_target): PRIVATE_MODULE := $(my_target)
28# $(my_target): PRIVATE_OUTPUT := $(my_target_output)
29# $(my_target): PRIVATE_RETVAL := $(my_target_retval)
30# $(my_target): $(my_target_output) $(my_target_retval)
31#         $(PATH)/wrapper.sh \
32#           $(PRIVATE_MODULE) \
33#           $(PRIVATE_OUTPUT) \
34#           $(PRIVATE_RETVAL) \
35#           eval
36
37set -euo pipefail
38
39# Terminate with a fatal error.
40function fatal() {
41  echo "Fatal: $*"
42  exit 113
43}
44
45function main() {
46  local module="${1-}"; shift || fatal "missing argument: module"
47  local output="${1-}"; shift || fatal "missing argument: output"
48  local retval="${1-}"; shift || fatal "missing argument: retval"
49  local action="${1-}"; shift || fatal "missing argument: action"
50  # The rest of the arguments are the command to run.
51
52  if [ "$action" = 'wrap' ]; then
53    # Run the command specified by the rest of arguments ("$@") and save output
54    # and return value.
55    echo 0 >"${retval}"
56    "$@" >"${output}" 2>&1 || echo "$?" >"${retval}"
57
58    # Wrapping itself is always successful.
59    return
60  elif [ "$action" = 'eval' ]; then
61    local result="$(cat "${retval}")"
62    if [ "$result" = 0 ]; then
63      # If successful only print the last few lines.
64      tail -n 5 "$output" | sed -e "s/^/${module}: /"
65    else
66      # Print the entire output on failure.
67      cat "$output" | sed -e "s/^/${module}: /"
68    fi
69    # Evaluating returns the stored return value.
70    return "$result"
71  else
72    fatal "invalid action: $action"
73  fi
74}
75
76main "$@"
77