#!/usr/bin/env bash set -Eeuo pipefail end="\033[0m" red="\033[0;31m" red() { echo -e "${red}${1}${end}"; } ## Constant definitions JSON="${1:-}" [[ -z "${JSON}" ]] && { red 'Missing input JSON file.' cat < Arguments SITE_JSON_PATH Path to the site.json file which contains data and metadata about pages of the site. Examples: $0 _site/site.json $0 result/site.json $0 \$(nix-build -A subtasks.docs)/site.json EOF exit 2 } LANGS=(en pt fr) IGNORED_PAGES=(site.json sitemap.xml *.atom) ## Helper function definitions contains-element() { local e match="$1" shift for e; do [[ "$e" == "$match" ]] && return 0; done return 1 } fail-attr() { ATTRIBUTE="${1}" URL="${2}" red "Undefined '${ATTRIBUTE}' for ${URL}." >&2 exit 1 } get-lang() { echo "${1}" | base64 --decode | jq -r .lang } get-ref() { echo "${1}" | base64 --decode | jq -r .ref } get-url() { # Remove leading / to match more closely the filesystem hierarchy echo "${1}" | base64 --decode | jq -r .url | sed 's_^/__' } get-date() { echo "${1}" | base64 --decode | jq -r .date } get-title() { echo "${1}" | base64 --decode | jq -r .title } get-layout() { echo "${1}" | base64 --decode | jq -r .layout } ## Assertions assert-frontmatter() { F="${1}" LANG="$(get-lang "$F")" REF="$(get-ref "$F")" URL="$(get-url "$F")" [[ -z "${LANG}" ]] && fail-attr 'lang' "${URL}" [[ -z "${REF}" ]] && fail-attr 'ref' "${URL}" if ! contains-element "${URL}" "${IGNORED_PAGES[@]}"; then TITLE="$(get-title "$F")" [[ -z "${TITLE}" ]] && fail-attr 'title' "${URL}" fi if ! contains-element "${LANG}" "${LANGS[@]}"; then red "Invalid lang '${LANG}' in ${URL}." >&2 exit 1 fi } echo Linting posts... >&2 for post in $(jq -r '.posts[] | @base64' "${JSON}"); do assert-frontmatter "$post" DATE="$(get-date "$post" | awk '{print $1}')" URL="$(basename "$(get-url "$post")")" FILE="_posts/${DATE}-${URL%.html}.md" [[ -f "${FILE}" ]] || { red "date/filename mismatch: '${FILE}' does not exist." exit 1 } done echo Linting pages... >&2 for page in $(jq -r '.pages[] | @base64' "${JSON}"); do URL="$(get-url "$page")" if ! contains-element "${URL}" "${IGNORED_PAGES[@]}"; then assert-frontmatter "${page}" fi done echo Linting pastebins... >&2 for pastebin in $(jq -r '.pastebins[] | @base64' "${JSON}"); do assert-frontmatter "$pastebin" done echo Linting tils... >&2 for til in $(jq -r '.tils[] | @base64' "${JSON}"); do assert-frontmatter "$til" DATE="$(get-date "$til" | awk '{print $1}')" URL="$(basename "$(get-url "$til")")" FILE="_tils/${DATE}-${URL%.html}.md" [[ -f "${FILE}" ]] || { red "date/filename mismatch: '${FILE}' does not exist." exit 1 } done echo Asserting unique refs... >&2 KNOWN_IDS=() assert-unique-ref() { for page in $1; do URL="$(get-url "$page")" if ! contains-element "${URL}" "${IGNORED_PAGES[@]}"; then LANG="$(get-lang "$page")" REF="$(get-ref "$page")" ID="${LANG}:${REF}" if contains-element "${ID}" "${KNOWN_IDS[@]}"; then printf '%s\n' "${KNOWN_IDS[@]}" red "Duplicated lang:ref match: '${ID}'." >&2 red "Page: ${URL}." >&2 exit 1 fi KNOWN_IDS+=("${ID}") # printf '%s\n' "${KNOWN_IDS[@]}" fi done } assert-unique-ref "$(jq -r '.pages[] | @base64' "${JSON}")" assert-unique-ref "$(jq -r '.posts[] | @base64' "${JSON}")" assert-unique-ref "$(jq -r '.tils[] | @base64' "${JSON}")" echo Asserting layouts... >&2 assert-layout() { DESIRED=$2 for p in $1; do LAYOUT="$(get-layout "$p")" URL="$(get-url "$p")" if [[ "${DESIRED}" != "${LAYOUT}" ]]; then red "Layout mismatch: expected '${DESIRED}', got '${LAYOUT}'." red "Page: ${URL}." exit 1 fi done } assert-layout "$(jq -r '.posts[] | @base64' "${JSON}")" "post" assert-layout "$(jq -r '.pastebins[] | @base64' "${JSON}")" "pastebin" assert-layout "$(jq -r '.tils[] | @base64' "${JSON}")" "til" echo Done. >&2