#!/bin/bash # Diff two composed site outputs modulo the build clock. # # Normalised away, and only these: # - "generatedAt": "" in every JSON (compact and pretty forms) # - the archive zip's own bytes: entry mtimes are the build clock, so a zip # built twice differs by a byte or two even when its ENTRIES are identical. # Zips are therefore compared by unpacked, generatedAt-normalised contents, # and archives/manifest.json's `bytes` (the zip's size) with them. A=$1; B=$2 norm() { sed -E -e 's/"generatedAt": *"[^"]*"/"generatedAt":"X"/g' "$1"; } normarch() { sed -E -e 's/"generatedAt": *"[^"]*"/"generatedAt":"X"/g' -e 's/"bytes": *[0-9]+/"bytes":N/g' "$1"; } rc=0 ( cd "$A" && find . -type f | sort ) > /tmp/fa.$$ ( cd "$B" && find . -type f | sort ) > /tmp/fb.$$ if ! diff -q /tmp/fa.$$ /tmp/fb.$$ >/dev/null; then echo "FILE LIST DIFFERS"; diff /tmp/fa.$$ /tmp/fb.$$; rc=1; fi while read -r f; do if [[ "$f" == *.zip ]]; then ta=$(mktemp -d); tb=$(mktemp -d) unzip -qq -o "$A/$f" -d "$ta"; unzip -qq -o "$B/$f" -d "$tb" while read -r e; do if ! diff <(norm "$ta/$e") <(norm "$tb/$e") >/dev/null; then echo "ZIP ENTRY DIFFERS: $f!$e"; rc=1 fi done < <(cd "$ta" && find . -type f | sort) if ! diff <(cd "$ta" && find . -type f|sort) <(cd "$tb" && find . -type f|sort) >/dev/null; then echo "ZIP ENTRY LIST DIFFERS: $f"; rc=1; fi rm -rf "$ta" "$tb" elif [[ "$f" == ./archives/manifest.json ]]; then if ! diff <(normarch "$A/$f") <(normarch "$B/$f") >/dev/null; then echo "DIFFERS: $f"; diff <(normarch "$A/$f") <(normarch "$B/$f") | head -8; rc=1; fi elif ! diff <(norm "$A/$f") <(norm "$B/$f") >/dev/null; then echo "DIFFERS: $f"; diff <(norm "$A/$f") <(norm "$B/$f") | head -8; rc=1 fi done < /tmp/fa.$$ rm -f /tmp/fa.$$ /tmp/fb.$$ [ $rc -eq 0 ] && echo "IDENTICAL modulo the build clock ($(cd "$A" && find . -type f | wc -l) files)" exit $rc