#!/bin/sh
# script/discard-dist-on-failure: run one step of the RELEASE build, and if that
# step fails, remove dist/ before returning its exit status. Our own extension
# to scripts-to-rule-them-all, wrapped around every step of make build.
#
# Why: with AUTISTMASK_DEBUG=1 exported, make build compiles a debug bundle and
# then fails on it in script/verify-build, after the bundle is written. It is
# loadable, and every wallet it creates gets the publicly committed test
# recovery phrase from src/shared/constants.js, so a failed build must not leave
# it behind. The removal is never silent: it says on stderr that dist/ is gone
# and why.
#
# A failed check-censored --require-dist removes dist/ like any other step: a
# dist/ not cleared of the name RULES.md bars must not ship either. A step that
# succeeds removes nothing. An interrupt (Ctrl-C) while a step runs removes
# nothing and says nothing, even when the step catches it and exits with a
# status of its own: the wrapper exits with 130 once the step has ended. An
# interrupt is not a build failure, and whoever interrupted the build knows it
# did not finish. make build-debug is not wrapped: a debug build that failed is
# not a mistakable artifact, and its output is the evidence of what went wrong.
set -eu

ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
DIST="$ROOT/dist"

usage() {
    echo "usage: discard-dist-on-failure COMMAND [ARG...]" >&2
}

# Remove dist/, and say so. A removal that could not be completed is reported as
# loudly as one that was: the artifact is still on disk, and reporting nothing
# would leave the operator believing it is not.
discard_dist() {
    if [ ! -e "$DIST" ] && [ ! -h "$DIST" ]; then
        echo "discard-dist-on-failure: the release build failed. There was no" \
            "dist/ to remove." >&2
        return 0
    fi

    rm -rf "$DIST" || true

    if [ -e "$DIST" ] || [ -h "$DIST" ]; then
        echo "discard-dist-on-failure: the release build failed and dist/" \
            "COULD NOT BE REMOVED, so it is still on disk. Do not load it:" \
            "a release build that failed may hold a complete debug bundle," \
            "whose wallets all use the publicly committed test recovery" \
            "phrase. Remove it by hand (make clean)." >&2
        return 0
    fi

    echo "discard-dist-on-failure: the release build failed, so dist/ WAS" \
        "REMOVED and no longer exists. A release build that fails has often" \
        "already emitted a complete, loadable debug bundle — every wallet it" \
        "creates gets the publicly committed test recovery phrase — so the" \
        "failed build is not left behind to be loaded. Fix the failure and" \
        "re-run make build, or run make build-debug if a debug build is what" \
        "was wanted; that target keeps its output." >&2
}

main() {
    [ "$#" -ge 1 ] || {
        usage
        echo "discard-dist-on-failure: no command given, so no build step ran" \
            "and nothing was removed." >&2
        exit 1
    }

    # An interrupt is not a build failure: once the step has ended, exit
    # without removing anything, even if the step caught the interrupt and
    # exited with a status of its own. bash as /bin/sh would otherwise carry on.
    trap 'exit 130' INT

    _status=0
    "$@" || _status=$?

    [ "$_status" -ne 0 ] || return 0

    # A message that cannot be written, to a closed stderr or to a pipe nobody
    # reads any more, must not replace the step's status.
    trap '' PIPE
    discard_dist || true
    exit "$_status"
}

main "$@"
