#!/usr/bin/zsh

set -o nomatch
set -o pipefail

local status() {
  echo -e "$@"
}

local pre_hook() {
  status "CASILEPRE$target"
}

local post_hook() {
  status "CASILEPOST$target$2"
}

local report_stdout() {
  while read line; do
    echo -e "CASILESTDOUT$target$line"
  done
}

local report_stderr() {
  while read line; do
    echo -e "CASILESTDERR$target$line" >&2
  done
}

local process_recipe() {
  pre_hook $target
  {
    (
      set -e
      set -o nobadpattern
      [[ ! -v _debug ]] || set -x
      exec > >(report_stdout) 2> >(report_stderr)
      eval "$@"
      set +x
      # Shenanigans to force close the process substitutions and give them enough time to have flushed...
      # Without this the whole wrapper process is closing before the Rust process has finished iterating its output.
      exec >/dev/null 2>/dev/null
      sleep 0.05
    )
  } always {
    post_hook $target $?
  }
}

local process_shell() {
  (
    set -e
    set -o nobadpattern
    [[ ! -v _debug ]] || set -x
    eval "$@"
    set +x
  )
}

# GNU Make 4.4 started passing shell args as a single argument no matter how
# they are quoted. Since we want to process them ourselves, explode them here.
# for the purposes of our parsing off wrapper arguments, then use the final
# argument as the only one to be eval()'ed.
final=$argv[$#]
shift -p
argv=(${(z)argv} ${(z)final})

while true; do
  case $1 in
    '/bin/sh'|'-c')
      shift
      ;;
    '-x')
      _debug=true
      shift
      ;;
    'target='*)
      eval $1
      shift
      ;;
      # Bogus filler flag to force make to have at least one flag even if debug
      # isn't set hence forcing it to quote the actual shell code argument.
    '-w')
      shift
      ;;
    '_WRAPTARGET='*)
      final=${final##$1 }
      eval $1
      shift
      ;;
    *)
      break
      ;;
  esac
done

if ${_WRAPTARGET:-false} && [[ -v target ]]; then
  exec process_recipe $final
else
  exec process_shell $final
fi
