Files
2026-03-23 01:29:38 +03:00

83 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""
On Windows, case-colliding paths (for example Foo.h / foo.h) map to one file.
This repository contains many one-line wrapper headers used for Linux cross
builds. If a wrapper wins checkout on a case-insensitive filesystem, it can
self-include and strip required type definitions, causing massive compile
failures.
This script restores the "real" header content for each case-collision group
by reading blobs from HEAD and writing the non-wrapper variant to disk.
"""
from __future__ import annotations
import collections
import pathlib
import re
import subprocess
import sys
WRAPPER_RE = re.compile(
br"^\s*#pragma\s+once\s*(?:\r?\n)+\s*#include\s+[\"<]([^\">]+)[\">]\s*$",
re.S,
)
def git_lines(*args: str) -> list[str]:
return subprocess.check_output(["git", *args], text=True).splitlines()
def git_blob(path: str) -> bytes:
return subprocess.check_output(["git", "show", f"HEAD:{path}"])
def is_wrapper_blob(blob: bytes) -> bool:
return WRAPPER_RE.match(blob) is not None
def main() -> int:
files = git_lines("ls-files")
by_lower: dict[str, list[str]] = collections.defaultdict(list)
for path in files:
by_lower[path.lower()].append(path)
fixed_groups = 0
skipped_groups = 0
for variants in by_lower.values():
if len(variants) < 2:
continue
blobs: list[tuple[str, bytes, bool]] = []
for variant in variants:
blob = git_blob(variant)
blobs.append((variant, blob, is_wrapper_blob(blob)))
non_wrappers = [entry for entry in blobs if not entry[2]]
if not non_wrappers:
skipped_groups += 1
continue
# Keep the richest definition if there is more than one real variant.
_source_variant, source_blob, _ = max(non_wrappers, key=lambda entry: len(entry[1]))
# On case-insensitive filesystems any variant path points at the same file.
target = pathlib.Path(variants[0])
target.parent.mkdir(parents=True, exist_ok=True)
current = target.read_bytes() if target.exists() else b""
if current != source_blob:
target.write_bytes(source_blob)
fixed_groups += 1
print(
f"Case-collision normalization complete: fixed={fixed_groups}, skipped={skipped_groups}",
file=sys.stdout,
)
return 0
if __name__ == "__main__":
raise SystemExit(main())