|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Compare a Hakyll-generated site against a Zola-generated site. |
| 3 | +# Accounts for URL structure differences (flat .html vs directory/index.html). |
| 4 | +# |
| 5 | +# Usage: diff_sites.sh <hakyll_dir> <zola_dir> |
| 6 | + |
| 7 | +set -euo pipefail |
| 8 | + |
| 9 | +HAKYLL="${1:?Usage: diff_sites.sh <hakyll_dir> <zola_dir>}" |
| 10 | +ZOLA="${2:?Usage: diff_sites.sh <hakyll_dir> <zola_dir>}" |
| 11 | + |
| 12 | +# Colors |
| 13 | +RED='\033[0;31m' |
| 14 | +GREEN='\033[0;32m' |
| 15 | +YELLOW='\033[0;33m' |
| 16 | +CYAN='\033[0;36m' |
| 17 | +BOLD='\033[1m' |
| 18 | +NC='\033[0m' |
| 19 | + |
| 20 | +identical=0 |
| 21 | +differing=0 |
| 22 | +hakyll_only=0 |
| 23 | +zola_only=0 |
| 24 | + |
| 25 | +# Map a Hakyll relative path to the expected Zola relative path. |
| 26 | +hakyll_to_zola_path() { |
| 27 | + local h="$1" |
| 28 | + case "$h" in |
| 29 | + # Top-level pages: foo.html -> foo/index.html |
| 30 | + about.html) echo "about/index.html" ;; |
| 31 | + found.html) echo "found/index.html" ;; |
| 32 | + nfc.html) echo "nfc/index.html" ;; |
| 33 | + nfc-armband.html) echo "nfc-armband/index.html" ;; |
| 34 | + archive.html) echo "archive/index.html" ;; |
| 35 | + # Posts: posts/slug.html -> posts/slug/index.html |
| 36 | + posts/*.html) |
| 37 | + local slug="${h%.html}" |
| 38 | + echo "${slug}/index.html" |
| 39 | + ;; |
| 40 | + # These stay the same |
| 41 | + index.html | atom.xml | rss.xml | robots.txt | sitemap.xml) |
| 42 | + echo "$h" |
| 43 | + ;; |
| 44 | + # CSS: Hakyll css/default.css -> Zola default.css (compiled SASS) |
| 45 | + css/default.css) echo "default.css" ;; |
| 46 | + css/default.scss) echo "__SKIP__" ;; # source file, not in Zola output |
| 47 | + # Everything else: try same path |
| 48 | + *) echo "$h" ;; |
| 49 | + esac |
| 50 | +} |
| 51 | + |
| 52 | +echo -e "${BOLD}=== Site Diff: Hakyll vs Zola ===${NC}" |
| 53 | +echo -e "Hakyll: ${HAKYLL}" |
| 54 | +echo -e "Zola: ${ZOLA}" |
| 55 | +echo |
| 56 | + |
| 57 | +# --- Phase 1: Check Hakyll files against Zola --- |
| 58 | +echo -e "${BOLD}--- Hakyll files ---${NC}" |
| 59 | + |
| 60 | +while IFS= read -r hakyll_file; do |
| 61 | + rel="${hakyll_file#"$HAKYLL"/}" |
| 62 | + zola_rel=$(hakyll_to_zola_path "$rel") |
| 63 | + |
| 64 | + if [[ "$zola_rel" == "__SKIP__" ]]; then |
| 65 | + continue |
| 66 | + fi |
| 67 | + |
| 68 | + zola_file="${ZOLA}/${zola_rel}" |
| 69 | + |
| 70 | + if [[ ! -f "$zola_file" ]]; then |
| 71 | + echo -e " ${YELLOW}HAKYLL-ONLY${NC} ${rel} (expected: ${zola_rel})" |
| 72 | + ((hakyll_only++)) || true |
| 73 | + continue |
| 74 | + fi |
| 75 | + |
| 76 | + # Binary or text comparison |
| 77 | + case "$rel" in |
| 78 | + *.html | *.xml | *.css | *.txt) |
| 79 | + if diff -q <(sed 's/[[:space:]]*$//' "$hakyll_file") \ |
| 80 | + <(sed 's/[[:space:]]*$//' "$zola_file") &>/dev/null; then |
| 81 | + echo -e " ${GREEN}IDENTICAL${NC} ${rel}" |
| 82 | + ((identical++)) || true |
| 83 | + else |
| 84 | + echo -e " ${RED}DIFFERENT${NC} ${rel} <-> ${zola_rel}" |
| 85 | + ((differing++)) || true |
| 86 | + # Show first 30 lines of diff |
| 87 | + diff -u \ |
| 88 | + --label "hakyll/${rel}" \ |
| 89 | + --label "zola/${zola_rel}" \ |
| 90 | + <(sed 's/[[:space:]]*$//' "$hakyll_file") \ |
| 91 | + <(sed 's/[[:space:]]*$//' "$zola_file") \ |
| 92 | + | head -60 || true |
| 93 | + echo |
| 94 | + fi |
| 95 | + ;; |
| 96 | + *) |
| 97 | + if cmp -s "$hakyll_file" "$zola_file"; then |
| 98 | + echo -e " ${GREEN}IDENTICAL${NC} ${rel}" |
| 99 | + ((identical++)) || true |
| 100 | + else |
| 101 | + echo -e " ${RED}DIFFERENT${NC} ${rel} <-> ${zola_rel} (binary)" |
| 102 | + ((differing++)) || true |
| 103 | + fi |
| 104 | + ;; |
| 105 | + esac |
| 106 | +done < <(find "$HAKYLL" -type f | sort) |
| 107 | + |
| 108 | +# --- Phase 2: Check for Zola-only files --- |
| 109 | +echo |
| 110 | +echo -e "${BOLD}--- Zola-only files (not in Hakyll) ---${NC}" |
| 111 | + |
| 112 | +# Build a set of expected Zola paths from Hakyll |
| 113 | +declare -A expected_zola_paths |
| 114 | +while IFS= read -r hakyll_file; do |
| 115 | + rel="${hakyll_file#"$HAKYLL"/}" |
| 116 | + zola_rel=$(hakyll_to_zola_path "$rel") |
| 117 | + if [[ "$zola_rel" != "__SKIP__" ]]; then |
| 118 | + expected_zola_paths["$zola_rel"]=1 |
| 119 | + fi |
| 120 | +done < <(find "$HAKYLL" -type f | sort) |
| 121 | + |
| 122 | +while IFS= read -r zola_file; do |
| 123 | + rel="${zola_file#"$ZOLA"/}" |
| 124 | + if [[ -z "${expected_zola_paths[$rel]+x}" ]]; then |
| 125 | + echo -e " ${CYAN}ZOLA-ONLY${NC} ${rel}" |
| 126 | + ((zola_only++)) || true |
| 127 | + fi |
| 128 | +done < <(find "$ZOLA" -type f | sort) |
| 129 | + |
| 130 | +# --- Summary --- |
| 131 | +echo |
| 132 | +echo -e "${BOLD}=== Summary ===${NC}" |
| 133 | +echo -e " ${GREEN}Identical${NC}: ${identical}" |
| 134 | +echo -e " ${RED}Different${NC}: ${differing}" |
| 135 | +echo -e " ${YELLOW}Hakyll-only${NC}: ${hakyll_only}" |
| 136 | +echo -e " ${CYAN}Zola-only${NC}: ${zola_only}" |
| 137 | + |
| 138 | +if ((differing > 0 || hakyll_only > 0)); then |
| 139 | + exit 1 |
| 140 | +fi |
0 commit comments