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.
112 lines
4.1 KiB
Bash
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
|