#!/usr/bin/env bash # # Bisect parsing a file at various line cut-off points to see which line causes the parse to differ from emacs. set -euo pipefail IFS=$'\n\t' DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$DIR/../" REALPATH=$(command -v uu-realpath || command -v realpath) ############## Setup ######################### function cleanup { for f in "${folders[@]}"; do log "Deleting $f" rm -rf "$f" done } folders=() for sig in EXIT INT QUIT HUP TERM; do trap "set +e; cleanup" "$sig" done function die { local status_code="$1" shift (>&2 echo "${@}") exit "$status_code" } function log { (>&2 echo "${@}") } ############## Program ######################### function main { log "Is is recommended that the output of \`mktemp -d -t 'compare_bisect.XXXXXXXX'\` is inside a tmpfs filesystem since this script will make many writes to these folders." local target_full_path=$($REALPATH "$1") SOURCE_FOLDER=$(dirname "$target_full_path") TARGET_DOCUMENT=$(basename "$target_full_path") local good=0 local bad=$(wc -l "$SOURCE_FOLDER/$TARGET_DOCUMENT" | awk '{print $1}') set +e run_parse "$bad" &> /dev/null local status=$? set -e if [ $status -eq 0 ]; then log "Entire file passes." exit 0 fi while [[ "$((bad - good))" -gt 1 ]]; do local next_line=$((((bad - good) / 2) + good)) log "Testing line $next_line" set +e run_parse "$next_line" &> /dev/null local status=$? set -e if [ $status -eq 0 ]; then good="$next_line" log "Line $next_line good" else bad="$next_line" log "Line $next_line bad" fi done echo "Bad line: $bad" } function setup_temp_dir { local temp_dir=$(mktemp -d -t 'compare_bisect.XXXXXXXX') cp -r "$SOURCE_FOLDER/"* "$temp_dir/" echo "$temp_dir" } function run_parse { local lines="$1" local temp_dir=$(setup_temp_dir) folders+=("$temp_dir") cat "$SOURCE_FOLDER/$TARGET_DOCUMENT" | head -n "$lines" > "$temp_dir/$TARGET_DOCUMENT" "${DIR}/run_docker_compare.bash" "$temp_dir/$TARGET_DOCUMENT" local status=$? rm -rf "$temp_dir" # TODO: Remove temp_dir from folders return "$status" } main "${@}"