#!/usr/bin/env python3
"""Assemble debian/copyright from debian/copyright.header and the
per-crate DEP-5 fragments in debian/copyright.in.d/.

Usage: debian/bin/merge-copyright > debian/copyright

Each fragment in debian/copyright.in.d/<crate> may contain zero or more
"Files:" stanzas and zero or more stand-alone "License:" stanzas (full
license text referenced by short name from one or more Files stanzas).
Stand-alone License stanzas are deduplicated across fragments: two
stanzas for the same short name are merged into one if their text is
identical once whitespace is collapsed; a genuine mismatch is reported
as an error so it can be fixed by hand.
"""
import glob
import os
import sys

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
HEADER = os.path.join(ROOT, "copyright.header")
FRAGMENT_DIR = os.path.join(ROOT, "copyright.in.d")


def split_stanzas(text):
    """Split a DEP-5 file's text into a list of stanzas (each a list of
    lines, blank separator lines removed)."""
    stanzas = []
    current = []
    for line in text.splitlines():
        if line.strip() == "":
            if current:
                stanzas.append(current)
                current = []
        else:
            current.append(line)
    if current:
        stanzas.append(current)
    return stanzas


def normalize(lines):
    return "\n".join(line.strip() for line in lines if line.strip() != "")


def main():
    with open(HEADER, encoding="utf-8") as f:
        header_text = f.read().rstrip("\n")

    files_stanzas = []
    # short_name -> (original_stanza_lines, normalized_text)
    license_stanzas = {}
    errors = []

    for path in sorted(glob.glob(os.path.join(FRAGMENT_DIR, "*"))):
        crate = os.path.basename(path)
        with open(path, encoding="utf-8") as f:
            text = f.read()
        for stanza in split_stanzas(text):
            first = stanza[0]
            if first.startswith("Files:"):
                files_stanzas.append(stanza)
            elif first.startswith("License:"):
                short_name = first[len("License:"):].strip()
                norm = normalize(stanza[1:])
                if short_name in license_stanzas:
                    _, existing_norm = license_stanzas[short_name]
                    if existing_norm != norm:
                        errors.append(
                            f"conflicting License text for '{short_name}' "
                            f"(first seen before crate '{crate}')"
                        )
                else:
                    license_stanzas[short_name] = (stanza, norm)
            else:
                errors.append(
                    f"{crate}: stanza does not start with Files: or License: "
                    f"({first!r})"
                )

    if errors:
        for e in errors:
            print(f"merge-copyright: error: {e}", file=sys.stderr)
        sys.exit(1)

    out = [header_text]
    for stanza in files_stanzas:
        out.append("\n".join(stanza))
    for short_name in sorted(license_stanzas):
        stanza, _ = license_stanzas[short_name]
        out.append("\n".join(stanza))

    print("\n\n".join(out))


if __name__ == "__main__":
    main()
