From f396b873a8db4ca4d9d224ce423d33abf9e5227d Mon Sep 17 00:00:00 2001 From: Mr Robot Date: Mon, 12 Oct 2026 22:44:16 +0000 Subject: [PATCH] Keep ANGLE patches LF on Windows checkouts --- .gitattributes | 2 ++ .github/workflows/build.yml | 1 + scripts/build-windows.ps1 | 2 ++ tests/test-patch-checkout.py | 52 ++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 .gitattributes create mode 100644 tests/test-patch-checkout.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..cb919b1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Patches must retain LF even when Git for Windows enables core.autocrlf. +*.patch text eol=lf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a539dd..9f45e39 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -187,6 +187,7 @@ jobs: shell: bash run: | set -euo pipefail + python3 tests/test-patch-checkout.py for patch in patches/*.patch; do git -C build/angle apply --check "$GITHUB_WORKSPACE/$patch" git -C build/angle apply "$GITHUB_WORKSPACE/$patch" diff --git a/scripts/build-windows.ps1 b/scripts/build-windows.ps1 index 8fc5f2d..be3f5da 100644 --- a/scripts/build-windows.ps1 +++ b/scripts/build-windows.ps1 @@ -208,6 +208,8 @@ try { continue } + # Repeat the failed check without suppressing Git's hunk diagnostics. + git apply --check $patch.FullName throw "Patch does not apply cleanly: $($patch.FullName)" } } diff --git a/tests/test-patch-checkout.py b/tests/test-patch-checkout.py new file mode 100644 index 0000000..ceac332 --- /dev/null +++ b/tests/test-patch-checkout.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +"""Check Windows-style patch checkout and apply against the pinned ANGLE tree.""" +import os +from pathlib import Path +import subprocess +import tempfile + +ROOT = Path(__file__).resolve().parents[1] +ANGLE = Path(os.environ.get("ANGLE_DIR", str(ROOT / "build/angle"))) +PIN = (ROOT / "ANGLE_COMMIT").read_text().strip() + + +def git(*args, cwd): + return subprocess.check_output(["git", *args], cwd=cwd) + + +with tempfile.TemporaryDirectory(prefix="angle-patch-checkout-") as tmp: + tmp = Path(tmp) + patch_repo = tmp / "patches" + patch_repo.mkdir() + git("init", "-q", cwd=patch_repo) + # Copy only the inputs to a disposable repo so no real index/config is changed. + (patch_repo / ".gitattributes").write_bytes((ROOT / ".gitattributes").read_bytes()) + for patch in sorted((ROOT / "patches").glob("*.patch")): + (patch_repo / patch.name).write_bytes(patch.read_bytes()) + git("add", ".", cwd=patch_repo) + + for autocrlf in ("false", "true"): + checkout = tmp / ("checkout-" + autocrlf) + checkout.mkdir() + git("-c", "core.autocrlf=" + autocrlf, "checkout-index", "--all", + "--prefix=" + str(checkout) + "/", cwd=patch_repo) + sources = tmp / ("sources-" + autocrlf) + sources.mkdir() + git("init", "-q", cwd=sources) + patches = sorted(checkout.glob("*.patch")) + assert patches, "No patches found" + for patch in patches: + data = patch.read_bytes() + assert b"\r\n" not in data, f"{patch.name} checked out with CRLF" + for line in data.decode().splitlines(): + if line.startswith("--- a/"): + name = line[6:] + dest = sources / name + if not dest.exists(): + dest.parent.mkdir(parents=True, exist_ok=True) + dest.write_bytes(git("show", PIN + ":" + name, cwd=ANGLE)) + for patch in patches: + git("apply", "--check", str(patch), cwd=sources) + git("apply", str(patch), cwd=sources) + git("apply", "--reverse", "--check", str(patch), cwd=sources) + print(f"PASS: core.autocrlf={autocrlf}: LF checkout and all patches apply")