sirius-press/tools/refresh-patches.sh
Silent Mode 8e17bc6514 fix(sirius-press): pin line endings, found by cloning the published repo
Cloning the forge repo on Windows and running the suite there turned up two
things a checkout inside the monorepo could never show, because this working
copy has core.autocrlf=false.

Git on Windows defaults to autocrlf=true, so a fresh clone gets CRLF. For
most files that is cosmetic. For shell scripts it is not: install.sh copied
from such a clone onto a server fails with `bash: \r: command not found`,
which tells the person almost nothing about what is wrong. And a
CRLF-rewritten .patch file is no longer the bytes `patch` was given.

.gitattributes now pins eol=lf for the scripts, the container inputs and the
source, and marks *.patch as binary so nothing rewrites it at all.

tools/refresh-patches.sh --check also compares with --strip-trailing-cr, so
a clone made before this landed reports honestly instead of claiming the
patch record has drifted when it has not. A check that cries wolf is a check
somebody switches off.
2026-09-21 03:31:16 +02:00

112 lines
4.1 KiB
Bash

#!/usr/bin/env bash
# refresh-patches.sh — regenerate patches/ from what the fork actually changed.
#
# Since core is vendored, `patches/` is no longer how the build works — it is
# documentation. It answers the question anyone auditing this fork asks first:
# *what exactly did you change inside WordPress?* A directory of readable
# diffs answers that in a minute; `git log wordpress/` does not, because it is
# mostly upstream imports.
#
# Documentation that is generated stays true. Documentation that is maintained
# by hand drifts, and a stale record of a fork's core diff is worse than none,
# because people trust it.
#
# tools/refresh-patches.sh # rewrite patches/ from the tree
# tools/refresh-patches.sh --check # fail if it would change anything (CI)
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
repo="$(git -C "$here" rev-parse --show-toplevel)"
# Ask git where we are rather than subtracting paths: on Windows
# --show-toplevel answers "D:/..." while $PWD is "/d/...", and the
# subtraction silently leaves an absolute path behind.
prefix="$(cd "$here" && git rev-parse --show-prefix)wordpress"
UPSTREAM_BRANCH="sirius-press/wordpress-upstream"
CHECK=0
for arg in "$@"; do
case "$arg" in
--check) CHECK=1 ;;
*) echo "unknown option: $arg" >&2; exit 2 ;;
esac
done
say() { printf '\033[1m→\033[0m %s\n' "$*"; }
die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }
git -C "$repo" rev-parse --verify --quiet "$UPSTREAM_BRANCH" >/dev/null \
|| die "the branch $UPSTREAM_BRANCH is missing; there is nothing to diff against."
# shellcheck source=wordpress.lock
source "$here/tools/wordpress.lock"
staging="$here/dist/.patch-refresh"
rm -rf "$staging"
mkdir -p "$staging"
say "comparing ${prefix}/ against pristine WordPress ${WP_VERSION}"
# Every path that differs between the vendored tree and the pristine import.
#
# Compared tree to tree, not commit to commit: the upstream branch keeps
# WordPress at its root while the subtree keeps it under a prefix, so a
# plain `git diff BRANCH HEAD -- <prefix>` compares two different path
# spaces and reports the whole distribution as added.
UPSTREAM_TREE="${UPSTREAM_BRANCH}^{tree}"
VENDORED_TREE="HEAD:${prefix}"
mapfile -t changed < <(
git -C "$repo" diff --name-only "$UPSTREAM_TREE" "$VENDORED_TREE"
)
if [ ${#changed[@]} -eq 0 ]; then
say "the fork changes nothing in core — writing an empty series"
fi
index=0
for file in "${changed[@]}"; do
[ -n "$file" ] || continue
index=$((index + 1))
slug="$(echo "$file" | tr '/.' '--' | tr -cd 'A-Za-z0-9-')"
out="$staging/$(printf '%04d' "$index")-${slug}.patch"
{
echo "Subject: [PATCH] ${file}"
echo
echo "The fork's change to this file, regenerated by tools/refresh-patches.sh."
echo "It is a record, not the mechanism: core is vendored under wordpress/ and"
echo "this diff is what distinguishes it from pristine upstream."
echo
echo "Applies to: WordPress ${WP_VERSION}"
git -C "$repo" diff "$UPSTREAM_TREE" "$VENDORED_TREE" -- "$file" | tail -n +3
} > "$out"
done
if [ "$CHECK" -eq 1 ]; then
# --strip-trailing-cr because a Windows checkout may hold these with CRLF
# while what we just generated has LF. .gitattributes marks *.patch as
# binary to stop that happening, but a clone made before that landed — or
# with the file copied around by hand — would otherwise report drift that
# is not there, and a check that cries wolf gets switched off.
if diff -rq --strip-trailing-cr "$here/patches" "$staging" >/dev/null 2>&1; then
say "patches/ matches the tree"
rm -rf "$staging"
exit 0
fi
diff -ru --strip-trailing-cr "$here/patches" "$staging" || true
rm -rf "$staging"
die "patches/ is out of date. Run tools/refresh-patches.sh and commit the result."
fi
rm -f "$here/patches"/*.patch
if [ "$index" -gt 0 ]; then
cp "$staging"/*.patch "$here/patches/"
fi
rm -rf "$staging"
say "wrote ${index} patch file(s) describing the fork's core diff"
for f in "$here/patches"/*.patch; do
[ -e "$f" ] || continue
printf ' %s (%s lines)\n' "$(basename "$f")" "$(grep -c '' "$f")"
done