#!/bin/sh
# SPDX-FileCopyrightText: 2026 Jason Self <j@jxself.org>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Keep debian/copyright in step with the source tree's own SPDX headers, so
# the packaging metadata cannot silently drift from what the files declare.
#
# Invariant: the set of files debian/copyright places in the dual
# "GPL-3.0-or-later and Expat" stanza (the files that incorporate the original
# C# Trizbort code) must be exactly the set of source files whose own header
# declares "SPDX-License-Identifier: GPL-3.0-or-later AND MIT" (Expat is the
# DEP-5 name for the MIT text). In addition, every literal (non-wildcard) path
# named anywhere in debian/copyright must exist.
#
# Pure source-tree check: no build, no binary, no network. Run both from CI
# (.github/workflows/ci.yml) and as a Debian autopkgtest (debian/tests/
# control). POSIX sh; needs only awk, grep, sort and comm.
set -eu

# Resolve the source root from this script's own location, so it works both
# from the repo root (CI) and from the unpacked source tree (autopkgtest),
# whatever the current directory is.
root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
cd "$root"

copyright=debian/copyright
dual_license='GPL-3.0-or-later and Expat'
dual_spdx='GPL-3.0-or-later AND MIT'

if [ ! -f "$copyright" ]; then
    echo "error: $copyright not found (looked in $root)" >&2
    exit 2
fi

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

# 1. Paths that debian/copyright places in the dual-license stanza. Walk the
#    DEP-5 stanzas (blank-line separated) and, for the one whose License is the
#    dual license, print its Files paths.
awk -v want="$dual_license" '
    function flush() {
        if (lic == want)
            for (i = 1; i <= nf; i++) print files[i]
        nf = 0; lic = ""; field = ""
    }
    /^[[:space:]]*$/ { flush(); next }
    /^Files:/ {
        field = "Files"
        rest = $0; sub(/^Files:[[:space:]]*/, "", rest)
        if (rest != "") files[++nf] = rest
        next
    }
    /^License:/ {
        field = "License"
        lic = $0; sub(/^License:[[:space:]]*/, "", lic); sub(/[[:space:]]+$/, "", lic)
        next
    }
    /^[A-Za-z][A-Za-z0-9-]*:/ { field = "other"; next }
    /^[[:space:]]/ {
        if (field == "Files") {
            p = $0; sub(/^[[:space:]]+/, "", p); sub(/[[:space:]]+$/, "", p)
            if (p != "") files[++nf] = p
        }
        next
    }
    END { flush() }
' "$copyright" | sort -u > "$work/listed"

# 2. Source files whose own SPDX header declares the dual license. Every file
#    that incorporates Trizbort code is C++ under src/, which is also where all
#    dual-stanza paths point; scanning src/ keeps the check free of any
#    build-artifact false positives.
grep -rlI "SPDX-License-Identifier:[[:space:]]*$dual_spdx" src \
    | sort -u > "$work/declared" || true

status=0

added=$(comm -13 "$work/listed" "$work/declared" || true)
if [ -n "$added" ]; then
    status=1
    echo "error: these files declare '$dual_spdx' in their header but are" >&2
    echo "       missing from the dual-license stanza of $copyright:" >&2
    echo "$added" | sed 's/^/         /' >&2
fi

stale=$(comm -23 "$work/listed" "$work/declared" || true)
if [ -n "$stale" ]; then
    status=1
    echo "error: these files are in the dual-license stanza of $copyright but" >&2
    echo "       no longer declare '$dual_spdx' (removed, renamed or relicensed?):" >&2
    echo "$stale" | sed 's/^/         /' >&2
fi

# 3. Every literal (non-glob) path named anywhere in debian/copyright must
#    exist, so a deleted or renamed file cannot leave a dangling entry behind.
missing=$(awk '
    /^[[:space:]]*$/ { field = ""; next }
    /^Files:/ {
        field = "Files"
        rest = $0; sub(/^Files:[[:space:]]*/, "", rest)
        if (rest != "") print rest
        next
    }
    /^[A-Za-z][A-Za-z0-9-]*:/ { field = "other"; next }
    /^[[:space:]]/ {
        if (field == "Files") {
            p = $0; sub(/^[[:space:]]+/, "", p); sub(/[[:space:]]+$/, "", p)
            if (p != "") print p
        }
        next
    }
' "$copyright" | while IFS= read -r p; do
    case "$p" in
        *"*"*) continue ;;   # skip globs such as "*" and "debian/*"
    esac
    [ -e "$p" ] || printf '%s\n' "$p"
done)
if [ -n "$missing" ]; then
    status=1
    echo "error: these paths are named in $copyright but do not exist:" >&2
    echo "$missing" | sed 's/^/         /' >&2
fi

if [ "$status" -eq 0 ]; then
    n=$(wc -l < "$work/listed" | tr -d ' ')
    echo "debian/copyright is consistent with the source SPDX headers" \
         "($n dual-licensed files)."
fi

exit "$status"
