#!/bin/bash

# temporary directory to store intermediate codeql artifacts
tmp_dir=$(mktemp -dt autobuild.XXXXX)

tried=()

function iter_dir() {
  ls "$1" 2>/dev/null
}

function dir_non_empty() {
  [[ -n "$(iter_dir "$1")" ]]
}

function at_exit() {
  if [[ "$?" == 0 ]]; then
    if [[ "${#tried[@]}" -gt 0 ]]; then
      # keep artifacts of failed trials in the scratch dir for debugging
      mv "$tmp_dir" "$CODEQL_EXTRACTOR_CPP_SCRATCH_DIR/autobuild_failed_trials"
    fi
  else
    # merge all artifacts from failed trials into the normal target directories
    for build in $(iter_dir "$tmp_dir"); do
      for dir in TRAP SCRATCH DIAGNOSTIC; do
        local dir_var=CODEQL_EXTRACTOR_CPP_${dir}_DIR
        [[ -d "${!dir_var}" ]] && [[ -d "$tmp_dir/$build/$dir/." ]] && cp -faL "$tmp_dir/$build/$dir/." "${!dir_var}"
      done
    done
    rm -rf "$tmp_dir"
  fi
}

trap at_exit EXIT

function diagnose() {
  "$CODEQL_EXTRACTOR_CPP_ROOT/tools/diagnostics/diagnose-build.sh" "$@"
}

function try_build() {
  local name=$1
  echo "trying to build with $@" >&2
  tried+=("$name")
  "$@" 2>&1 | tee "$CODEQL_EXTRACTOR_CPP_SCRATCH_DIR/autobuild.out"
  local status=${PIPESTATUS[0]}
  diagnose "$name" "$CODEQL_EXTRACTOR_CPP_SCRATCH_DIR/autobuild.out"
  [[ "$status" == 0 ]] && exit 0
  # if command failed, move target directories in the designated temporary directory
  mkdir -p "$tmp_dir/$name"
  for dir in TRAP SCRATCH DIAGNOSTIC; do
    local dir_var=CODEQL_EXTRACTOR_CPP_${dir}_DIR
    if [[ -d "${!dir_var}" ]]; then
      mv -f "${!dir_var}" "$tmp_dir/$name/$dir"
      mkdir -p ${!dir_var}
    fi
  done
}

function join() {
  local d=${1-} f=${2-}
  if shift 2; then
    printf %s "$f" "${@/#/$d}"
  fi
}

function emit_diagnostics() {
  "$CODEQL_EXTRACTOR_CPP_ROOT/tools/diagnostics/emit.sh" "$@"
}

function tried_everything() {
  if [[ "${#tried[@]}" != 0 ]]; then
    emit_diagnostics build-command-failed '`'"$(join '`, `' "${tried[@]}")"'`'
  else
    emit_diagnostics no-build-command
  fi
  exit 1
}
