build(sirius-press): build from the vendored subtree instead of a download

The subtree is in place, so everything that used to fetch and patch core at
build time now just copies it.

  tools/build.sh        copies wordpress/ — no download, no checksum step,
                        because there is nothing to fetch and nothing to
                        trust that is not already in the repository
  docker/Dockerfile     COPY wordpress/ instead of curl + sha256 + patch;
                        the build args and the `patch` package are gone
  docker-compose.yml    no WP_VERSION / WP_URL / WP_SHA256 to keep in step

tools/update-wordpress.sh is rewritten around what the subtree makes
possible. It imports the pristine release onto sirius-press/wordpress-upstream
and then `git subtree merge`s that branch, which three-way merges upstream
against the fork's own commit. A patch either applies with fuzz and hopes or
fails and leaves you re-deriving the change by hand; a merge conflict is
resolved once, in the file, and the next release merges against the
resolution.

patches/ survives as documentation rather than mechanism, and is now
generated: tools/refresh-patches.sh diffs the subtree against the pristine
import and rewrites the directory, with --check for CI. It answers the
question anyone auditing a fork asks first — what exactly did you change
inside WordPress? — in a minute, which `git log wordpress/` cannot, because
that log is mostly upstream imports. Generated documentation stays true; a
hand-maintained record of a core diff drifts, and a stale one is worse than
none because people trust it.

One test change worth noting: the syntax sweep no longer walks all of
wordpress/. It lints the fork's own PHP plus every core file patches/ says
the fork touches, which keeps the suite at seven seconds instead of a minute
while still covering the only core file that can break.
This commit is contained in:
Silent Mode 2026-09-21 03:19:28 +02:00
parent 34fd3f062c
commit 961cb108ca
12 changed files with 396 additions and 376 deletions

View file

@ -121,7 +121,8 @@ plugins/
sirius-press-sia-export/ the static export queue and uploader sirius-press-sia-export/ the static export queue and uploader
sirius-press-compat/ shims for plugins that insist on an admin email sirius-press-compat/ shims for plugins that insist on an admin email
mu-plugins/ the bits that must load before plugins do mu-plugins/ the bits that must load before plugins do
patches/ the core diff — currently one file wordpress/ WordPress itself, vendored as a subtree, patched
patches/ a generated record of the core diff — one file
docker/ compose stack: MariaDB, PHP-FPM, nginx docker/ compose stack: MariaDB, PHP-FPM, nginx
tools/ build, upstream update, release tools/ build, upstream update, release
tests/ 138 unit checks plus a live end-to-end suite tests/ 138 unit checks plus a live end-to-end suite
@ -130,19 +131,20 @@ docs/
### Where WordPress itself is ### Where WordPress itself is
Not in this repository. `tools/wordpress.lock` pins an exact upstream version In `wordpress/`, as a git subtree, already patched. That is what gets built
and its SHA-256; `tools/build.sh` and the Docker image each download it, verify and what gets shipped — there is no download step and no checksum to trust at
the hash, and apply `patches/`. build time.
This deviates from the original plan of vendoring core as a git subtree, and Upstream releases arrive through `git subtree merge` against a branch of
the reason is arithmetic: WordPress 7.1.1 is 149 MB and 5,008 files, and the pristine imports, which three-way merges them against the fork's own commit
fork's entire core diff is 75 lines in one file. Carrying the former to express on top. `tools/update-wordpress.sh <version>` does the whole thing;
the latter would make every clone, every `git status` and every subtree split `patches/` keeps a generated, readable record of the 75 lines that differ
in the parent monorepo pay for a patch you can read in a minute. Upstream from stock WordPress, so nobody has to read a 3,800-file log to find out what
security releases still merge cleanly — `tools/update-wordpress.sh` bumps the this fork changes in core.
pin, reapplies the series with fuzz, and tells you exactly which hunk needs a
human if one does. [docs/upstream-merges.md](docs/upstream-merges.md) covers The trade is repository size — WordPress is about 149 MB. Worth it for a fork
the procedure and how to switch to a vendored subtree if you would rather. that can absorb a security release in a minute.
[docs/upstream-merges.md](docs/upstream-merges.md) has the procedure.
--- ---

View file

@ -32,8 +32,6 @@ WP_DEBUG=false
# It is not the phrase itself and is useless without the database. # It is not the phrase itself and is useless without the database.
SIRIUS_PRESS_KEY= SIRIUS_PRESS_KEY=
# --- core pin --------------------------------------------------------------- # WordPress itself is vendored in the repository (wordpress/) and baked into
# Mirrors tools/wordpress.lock. Change both together, never just one. # the image, so there is no version or checksum to configure here. See
WP_VERSION=7.1.1 # docs/upstream-merges.md for how a new upstream release gets in.
WP_URL=https://wordpress.org/wordpress-7.1.1.tar.gz
WP_SHA256=3996fee13448ef12e07e9f0c77db2f655ffa1b7cde71c80a4965d3bf1fb956b3

View file

@ -1,13 +1,13 @@
# Sirius Press — PHP-FPM image with a verified, patched WordPress baked in. # Sirius Press — PHP-FPM image with the patched WordPress baked in.
# #
# The image builds core rather than inheriting the official `wordpress` image # Core comes from this repository's `wordpress/` subtree, not from a download
# on purpose. That image ships whatever WordPress version it was tagged with, # and not from the official `wordpress` image. That image ships whatever
# and the patch series here is pinned to an exact one; silently applying a # version it was tagged with, and the fork's core patch is pinned to an exact
# fork's patches to a different core is how a setup wizard ends up half # one; applying a fork's patch to a different core is how a setup wizard ends
# rewritten. Downloading the pinned tarball and checking its hash during the # up half rewritten. Copying the vendored tree makes the image contain exactly
# build makes the version an explicit, verifiable property of the image. # what `git log wordpress/` describes, with nothing fetched at build time.
# #
# Core is installed to /opt/sirius-press/core, not to the document root. The # Core is staged at /opt/sirius-press/core, not at the document root. The
# entrypoint copies it into place on every start, which is what makes # entrypoint copies it into place on every start, which is what makes
# `docker compose build --pull && up -d` a real upgrade: the usual layout, # `docker compose build --pull && up -d` a real upgrade: the usual layout,
# where the document root is itself a volume, pins core to whatever version # where the document root is itself a volume, pins core to whatever version
@ -20,14 +20,10 @@
FROM php:8.3-fpm-bookworm FROM php:8.3-fpm-bookworm
ARG WP_VERSION
ARG WP_URL
ARG WP_SHA256
RUN set -eux; \ RUN set -eux; \
apt-get update; \ apt-get update; \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
ca-certificates curl patch \ ca-certificates curl \
libfreetype6-dev libjpeg62-turbo-dev libpng-dev libwebp-dev \ libfreetype6-dev libjpeg62-turbo-dev libpng-dev libwebp-dev \
libzip-dev libgmp-dev libicu-dev \ libzip-dev libgmp-dev libicu-dev \
; \ ; \
@ -49,29 +45,24 @@ RUN { \
echo 'expose_php = Off'; \ echo 'expose_php = Off'; \
} > /usr/local/etc/php/conf.d/sirius-press.ini } > /usr/local/etc/php/conf.d/sirius-press.ini
# --- core, verified ----------------------------------------------------------- # --- core, from the subtree --------------------------------------------------
COPY wordpress/ /opt/sirius-press/core/
RUN set -eux; \ RUN set -eux; \
curl -fsSL -o /tmp/wp.tar.gz "$WP_URL"; \ test -f /opt/sirius-press/core/wp-includes/version.php; \
echo "$WP_SHA256 /tmp/wp.tar.gz" | sha256sum -c -; \ sed -n "s/.*wp_version = '\\(.*\\)'.*/\\1/p" \
mkdir -p /opt/sirius-press; \ /opt/sirius-press/core/wp-includes/version.php \
tar -xzf /tmp/wp.tar.gz -C /tmp; \ > /opt/sirius-press/core/.sirius-core-version; \
mv /tmp/wordpress /opt/sirius-press/core; \ echo "vendored WordPress $(cat /opt/sirius-press/core/.sirius-core-version)"
rm -rf /tmp/wp.tar.gz
# --- the fork ----------------------------------------------------------------- # --- the fork -----------------------------------------------------------------
#
# The patch is already applied in the subtree, so there is nothing to patch
# here. patches/ is carried for auditing, not for building.
WORKDIR /opt/sirius-press/core WORKDIR /opt/sirius-press/core
COPY patches/ /tmp/patches/
RUN set -eux; \
for p in /tmp/patches/*.patch; do \
patch -p1 -F3 --forward --silent < "$p" \
|| { echo "patch $p did not apply to WordPress $WP_VERSION"; exit 1; }; \
done; \
rm -rf /tmp/patches; \
echo "$WP_VERSION" > /opt/sirius-press/core/.sirius-core-version
COPY plugins/ /opt/sirius-press/core/wp-content/plugins/ COPY plugins/ /opt/sirius-press/core/wp-content/plugins/
COPY mu-plugins/ /opt/sirius-press/core/wp-content/mu-plugins/ COPY mu-plugins/ /opt/sirius-press/core/wp-content/mu-plugins/

View file

@ -3,9 +3,10 @@
# Three containers: MariaDB, PHP-FPM with the patched WordPress baked in, and # Three containers: MariaDB, PHP-FPM with the patched WordPress baked in, and
# nginx in front. Only nginx is published. # nginx in front. Only nginx is published.
# #
# The volume layout is the part worth reading. WordPress core lives in the # The volume layout is the part worth reading. WordPress core comes from the
# image, not in a volume, so `docker compose build --pull && up -d` genuinely # repository's `wordpress/` subtree, is baked into the image, and is refilled
# upgrades it — the usual arrangement, where the whole document root is a # into the document root on every start — so `docker compose build && up -d`
# genuinely upgrades it — the usual arrangement, where the whole document root is a
# volume, freezes core at whatever version first created the volume and turns # volume, freezes core at whatever version first created the volume and turns
# every security release into a manual migration. What people actually need to # every security release into a manual migration. What people actually need to
# keep — uploads, plugins and themes they installed, and wp-config.php — is # keep — uploads, plugins and themes they installed, and wp-config.php — is
@ -43,13 +44,6 @@ services:
build: build:
context: .. context: ..
dockerfile: docker/Dockerfile dockerfile: docker/Dockerfile
args:
# install.sh copies these out of tools/wordpress.lock into .env.
# Defaults are pinned here too, so a plain `docker compose build`
# cannot quietly drift onto a different core.
WP_VERSION: ${WP_VERSION:-7.1.1}
WP_URL: ${WP_URL:-https://wordpress.org/wordpress-7.1.1.tar.gz}
WP_SHA256: ${WP_SHA256:-3996fee13448ef12e07e9f0c77db2f655ffa1b7cde71c80a4965d3bf1fb956b3}
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
db: db:

View file

@ -70,9 +70,9 @@ faster and signature verification sits on the login path.
tools/build.sh --zip tools/build.sh --zip
``` ```
Downloads the pinned WordPress, verifies its SHA-256, applies `patches/`, adds Copies the vendored WordPress out of `wordpress/`, adds the plugins, and
the plugins, and writes `dist/sirius-press-<version>.zip` alongside its writes `dist/sirius-press-<version>.zip` alongside its checksum. Nothing is
checksum. downloaded — core is in the repository.
--- ---
@ -129,9 +129,9 @@ git pull
cd docker && docker compose build && docker compose up -d cd docker && docker compose build && docker compose up -d
``` ```
Core, the fork's plugins and the patch series all come from the image, so this Core and the fork's plugins both come from the image, so this upgrades both.
upgrades all three. Your uploads, your database, your other plugins and themes, Your uploads, your database, your other plugins and themes, and
and `wp-config.php` live in volumes and are untouched. `wp-config.php` live in volumes and are untouched.
This is why the document root is refilled from the image on every start rather This is why the document root is refilled from the image on every start rather
than being a volume of its own — the usual WordPress-in-Docker layout pins core than being a volume of its own — the usual WordPress-in-Docker layout pins core

View file

@ -41,7 +41,7 @@ built-in server plus the official SQLite drop-in is enough, and it starts in
seconds. seconds.
```bash ```bash
# 1. a patched tree # 1. a complete tree (copied out of the vendored wordpress/, plugins added)
tools/build.sh tools/build.sh
cp -R dist/sirius-press /tmp/wpsite cp -R dist/sirius-press /tmp/wpsite

View file

@ -7,35 +7,33 @@ a liability rather than a project. This page is how Sirius Press takes them.
## The arrangement ## The arrangement
WordPress is not in this repository. Instead: WordPress lives in this repository, at `wordpress/`, as a **git subtree**. The
fork's own change sits on top of it as an ordinary commit.
- `tools/wordpress.lock` pins an exact version, its download URL and its Three pieces make that work:
SHA-256.
- `patches/` holds the fork's core diff as a patch series.
- `tools/build.sh` and the Docker image each download the pinned tarball,
verify the hash, and apply the series.
The entire core diff is currently **one file, 75 lines**: the setup wizard, at | | |
`wp-admin/install.php`. Everything else the fork does is plugins and hooks. |---|---|
| `wordpress/` | The vendored tree, patched. This is what gets built and shipped. |
| `sirius-press/wordpress-upstream` | A branch holding **pristine** upstream releases, one commit each, never edited. The other side of the merge. |
| `patches/` | A readable record of what the fork changes in core. Generated, not maintained. |
### Why not a vendored subtree The entire core diff is **one file, 75 lines**: `wp-admin/install.php`, the
setup wizard. Everything else Sirius Press does is plugins and hooks.
The original plan was to vendor core as a `git subtree`, which is the standard ### Why a subtree and not a patch series
way to run a fork with a substantial diff. Two numbers argued against it.
WordPress 7.1.1 is **149 MB and 5,008 files**. The fork's core diff is **75 Because a three-way merge understands something a patch does not. When
lines**. Carrying the first to express the second means every clone, every upstream edits lines near the fork's change, `git subtree merge` merges them
`git status`, every `git subtree split` in the parent monorepo pays for a patch and moves on; `patch` either applies with fuzz and hopes, or fails and hands
you can read in a minute — and it buries that patch in a haystack where nobody you the job of re-deriving the change by hand. A conflict from the merge is
will ever review it again. resolved once, in the file, and stays resolved — the next release merges
against the resolution.
A patch series makes the opposite trade. The core change is a file you can read The cost is repository size: WordPress is about 149 MB and 3,800 files. That
in one sitting, review in a pull request, and re-read whenever it stops is the price of a fork that can take a security release in a minute, and it is
applying. The cost is that upstream merges are `patch` rather than a three-way the right trade for a project whose whole argument is that it should outlive
git merge — which, for 75 lines in one file, is not much of a cost. its maintainers' attention.
This holds as long as the diff stays small. If the fork ever needs to change
core substantially, vendor it properly: see "Switching to a subtree" below.
--- ---
@ -45,46 +43,33 @@ core substantially, vendor it properly: see "Switching to a subtree" below.
tools/update-wordpress.sh 7.1.2 tools/update-wordpress.sh 7.1.2
``` ```
It fetches the release, verifies its SHA-1 against what wordpress.org It downloads the release, checks it against the SHA-1 wordpress.org publishes,
publishes, records a SHA-256, applies the patch series to the new tree, and imports the pristine tree onto `sirius-press/wordpress-upstream`, and merges
reports what happened. that branch into `wordpress/`. Then it updates `tools/wordpress.lock` and
regenerates `patches/`.
Three possible outcomes: Two outcomes.
**Clean.** The series applied. `tools/wordpress.lock` is updated, the tests **Clean.** The merge went through. Run the tests, build, commit. Usually a
run, and you commit the lock change. Usually thirty seconds of work. minute of work.
**Applied with fuzz.** Upstream moved code near a hunk but not the hunk itself. **Conflicted.** Upstream changed the same lines the fork changes — in
The script says which hunk and by how many lines. Look at the result, then practice, `wp-admin/install.php`. Git leaves the conflict in the file:
refresh the series so the next release starts from a clean base:
```bash ```bash
tools/update-wordpress.sh 7.1.2 --refresh git status
$EDITOR wordpress/wp-admin/install.php
git add wordpress/wp-admin/install.php
git commit
tools/refresh-patches.sh
``` ```
**Failed.** Upstream rewrote the code the patch touches. This is the case that Then set `WP_VERSION`, `WP_URL`, `WP_SHA256` and `WP_SHA1` in
needs a person: open the new `wp-admin/install.php`, redo the change by hand, `tools/wordpress.lock` by hand, since the script stopped before it got there.
and regenerate the patch. The script leaves the unpacked tree in
`dist/.upstream/` so there is something to work in.
In every case the fork is **not broken while you work** — the lock file still Either way the fork is **not broken while you work**: the merge is in your
points at the last known-good version, and builds keep producing that until you working tree, and until you commit it, `wordpress/` still holds the last
change it. version that worked.
---
## Reviewing a release before taking it
Security releases are usually small, and it is worth knowing what changed near
the code the fork patches:
```bash
tools/update-wordpress.sh 7.1.2 --diff wp-admin/install.php
```
prints upstream's own diff for that file between the pinned version and the new
one. If it is empty — which it usually is — the patch will apply and there is
nothing to think about.
--- ---
@ -92,42 +77,58 @@ nothing to think about.
```bash ```bash
tests/run.sh tests/run.sh
```
The suite does not test core, but it does test every assumption the fork makes
about it. Then build and try an actual install:
```bash
tools/build.sh tools/build.sh
cd docker && docker compose build && docker compose up -d
``` ```
and walk through `wp-admin/install.php` once. The setup wizard is the only The suite does not test core, but it tests every assumption the fork makes
patched file, so it is the only thing an upstream change can break in a way about it. Then walk through `wp-admin/install.php` once in a browser — the
the tests would miss. setup wizard is the only patched file, so it is the only thing an upstream
change can break in a way the tests would miss.
[testing.md](testing.md) has a recipe for a throwaway instance that needs no
database server.
--- ---
## Switching to a subtree ## Keeping `patches/` honest
If the diff ever grows past what a patch series is comfortable with, the `patches/` is documentation. It answers the question anyone auditing this fork
mechanics are: asks first — *what exactly did you change inside WordPress?* — in a minute,
which `git log wordpress/` cannot, because that log is mostly upstream
imports.
It is generated from the tree, never edited:
```bash ```bash
git remote add wordpress https://github.com/WordPress/WordPress.git tools/refresh-patches.sh # rewrite it
git fetch --depth=1 wordpress 7.1.1 tools/refresh-patches.sh --check # fail if it has drifted (for CI)
git subtree add --prefix=wordpress FETCH_HEAD --squash
``` ```
and then, per release: Generated documentation stays true. A hand-maintained record of a fork's core
diff drifts, and a stale one is worse than none, because people trust it.
---
## Changing core yourself
Edit the file under `wordpress/` and commit it like any other change. The next
upstream merge will three-way it.
Before you do: check whether a plugin hook can carry the change instead. Every
line added to `wordpress/` is a line that can conflict with upstream forever,
and the reason this fork's merges are cheap is that there are only 75 of them.
The registration form, the password-reset page and the mail pipeline were all
replaced from plugins precisely so they would never appear in this directory.
---
## If the upstream branch is missing
A clone made with `--single-branch` will not have
`sirius-press/wordpress-upstream`, and `tools/update-wordpress.sh` will say so
rather than guessing. Fetch it:
```bash ```bash
git fetch --depth=1 wordpress 7.1.2 git fetch origin sirius-press/wordpress-upstream:sirius-press/wordpress-upstream
git subtree merge --prefix=wordpress FETCH_HEAD --squash
``` ```
with `patches/` becoming the record of what was changed rather than the Building and running do not need it — only taking a new upstream release does.
mechanism that changes it. The build script would then copy `wordpress/`
instead of downloading and patching.
Worth doing when the core diff reaches, say, a dozen files. Not before.

View file

@ -1,31 +1,13 @@
Subject: [PATCH] setup wizard: ask for a wallet, not a mailbox Subject: [PATCH] wp-admin/install.php
The installer is the one place in WordPress where the fork cannot do its The fork's change to this file, regenerated by tools/refresh-patches.sh.
work from a plugin. It runs before plugins load, and it refuses to finish It is a record, not the mechanism: core is vendored under wordpress/ and
without an email address, so a site with no mail identity cannot be this diff is what distinguishes it from pristine upstream.
installed at all.
The change is the smallest one that removes the requirement:
- "Your Email" becomes "Your wallet address", and it is optional. The
installer has nothing to verify a signature against yet — the site
does not exist — so an address typed here is taken on trust and can be
replaced from the profile screen afterwards, where it CAN be proved.
- The two is_email() gates become one address check.
- wp_install() still receives an email string, because its signature and
everything downstream of it expects one. It gets a permanently
unroutable .invalid placeholder.
The two helper functions are defined by the Sirius Press bootstrap
must-use plugin, which loads before this file on every request including
the installer. If that plugin is missing, they fall back to accepting
nothing and the installer behaves as it does on stock WordPress minus the
email field.
Applies to: WordPress 7.1.1 Applies to: WordPress 7.1.1
--- a/wp-admin/install.php --- a/wp-admin/install.php
+++ b/wp-admin/install.php +++ b/wp-admin/install.php
@@ -101,6 +101,8 @@ @@ -101,6 +101,8 @@ function display_setup_form( $error = null ) {
$weblog_title = isset( $_POST['weblog_title'] ) ? trim( wp_unslash( $_POST['weblog_title'] ) ) : ''; $weblog_title = isset( $_POST['weblog_title'] ) ? trim( wp_unslash( $_POST['weblog_title'] ) ) : '';
$user_name = isset( $_POST['user_name'] ) ? trim( wp_unslash( $_POST['user_name'] ) ) : ''; $user_name = isset( $_POST['user_name'] ) ? trim( wp_unslash( $_POST['user_name'] ) ) : '';
$admin_email = isset( $_POST['admin_email'] ) ? trim( wp_unslash( $_POST['admin_email'] ) ) : ''; $admin_email = isset( $_POST['admin_email'] ) ? trim( wp_unslash( $_POST['admin_email'] ) ) : '';
@ -34,7 +16,7 @@ Applies to: WordPress 7.1.1
if ( ! is_null( $error ) ) { if ( ! is_null( $error ) ) {
?> ?>
@@ -175,9 +177,9 @@ @@ -175,9 +177,9 @@ function display_setup_form( $error = null ) {
</tr> </tr>
<?php endif; ?> <?php endif; ?>
<tr> <tr>
@ -47,7 +29,7 @@ Applies to: WordPress 7.1.1
</tr> </tr>
<?php $blog_privacy_selector_title = has_action( 'blog_privacy_selector' ) ? __( 'Site visibility' ) : __( 'Search engine visibility' ); ?> <?php $blog_privacy_selector_title = has_action( 'blog_privacy_selector' ) ? __( 'Site visibility' ) : __( 'Search engine visibility' ); ?>
<tr> <tr>
@@ -411,10 +413,20 @@ @@ -411,10 +413,20 @@ switch ( $step ) {
$user_name = isset( $_POST['user_name'] ) ? trim( wp_unslash( $_POST['user_name'] ) ) : ''; $user_name = isset( $_POST['user_name'] ) ? trim( wp_unslash( $_POST['user_name'] ) ) : '';
$admin_password = isset( $_POST['admin_password'] ) ? wp_unslash( $_POST['admin_password'] ) : ''; $admin_password = isset( $_POST['admin_password'] ) ? wp_unslash( $_POST['admin_password'] ) : '';
$admin_password_check = isset( $_POST['admin_password2'] ) ? wp_unslash( $_POST['admin_password2'] ) : ''; $admin_password_check = isset( $_POST['admin_password2'] ) ? wp_unslash( $_POST['admin_password2'] ) : '';
@ -70,7 +52,7 @@ Applies to: WordPress 7.1.1
$error = false; $error = false;
if ( empty( $user_name ) ) { if ( empty( $user_name ) ) {
// TODO: Poka-yoke. // TODO: Poka-yoke.
@@ -427,19 +439,20 @@ @@ -427,19 +439,20 @@ switch ( $step ) {
// TODO: Poka-yoke. // TODO: Poka-yoke.
display_setup_form( __( 'Your passwords do not match. Please try again.' ) ); display_setup_form( __( 'Your passwords do not match. Please try again.' ) );
$error = true; $error = true;

View file

@ -39,14 +39,28 @@ fi
bar "syntax" bar "syntax"
syntax_ok=1 syntax_ok=1
if command -v "$PHP_BIN" >/dev/null 2>&1; then if command -v "$PHP_BIN" >/dev/null 2>&1; then
# The fork's own PHP, plus every core file the fork patches. Sweeping all
# of wordpress/ would lint 3,800 files of upstream code that upstream
# already tests, and turn a one-second suite into a minute of waiting.
lint_targets() {
find "$here/../plugins" "$here/../mu-plugins" "$here" \
-name '*.php' -not -path '*/node_modules/*' 2>/dev/null
for patch in "$here"/../patches/*.patch; do
[ -e "$patch" ] || continue
sed -n 's|^--- a/||p' "$patch" | while IFS= read -r rel; do
case "$rel" in *.php) echo "$here/../wordpress/$rel" ;; esac
done
done
}
while IFS= read -r file; do while IFS= read -r file; do
[ -f "$file" ] || continue
if ! "$PHP_BIN" -l "$file" >/dev/null 2>&1; then if ! "$PHP_BIN" -l "$file" >/dev/null 2>&1; then
echo " FAIL $file" echo " FAIL $file"
"$PHP_BIN" -l "$file" 2>&1 | head -3 "$PHP_BIN" -l "$file" 2>&1 | head -3
syntax_ok=0 syntax_ok=0
status=1 status=1
fi fi
done < <(find "$here/.." -name '*.php' -not -path '*/dist/*' -not -path '*/node_modules/*') done < <(lint_targets)
fi fi
if command -v "$NODE_BIN" >/dev/null 2>&1; then if command -v "$NODE_BIN" >/dev/null 2>&1; then
while IFS= read -r file; do while IFS= read -r file; do
@ -55,9 +69,9 @@ if command -v "$NODE_BIN" >/dev/null 2>&1; then
syntax_ok=0 syntax_ok=0
status=1 status=1
fi fi
done < <(find "$here/.." -name '*.js' -not -path '*/dist/*' -not -path '*/node_modules/*') done < <(find "$here/../plugins" "$here" -name '*.js' -not -path '*/node_modules/*' 2>/dev/null)
fi fi
[ "$syntax_ok" -eq 1 ] && echo " ok every PHP and JS file parses" [ "$syntax_ok" -eq 1 ] && echo " ok the fork's PHP and JS parses, including every patched core file"
echo echo
if [ "$status" -eq 0 ]; then if [ "$status" -eq 0 ]; then

View file

@ -1,18 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# build.sh — assemble a complete, patched Sirius Press tree. # build.sh — assemble a complete Sirius Press tree.
# #
# Downloads the pinned WordPress, verifies it against the checksum in # Copies the vendored WordPress from wordpress/, drops this repository's
# tools/wordpress.lock, applies the patch series in patches/, drops this # plugins and must-use plugins into it, and leaves the result in
# repository's plugins and must-use plugins into place, and leaves the result # dist/sirius-press/.
# in dist/sirius-press/.
# #
# With --zip it also produces dist/sirius-press-<version>.zip, which is the # With --zip it also produces dist/sirius-press-<version>.zip, which is the
# artifact shared-hosting users upload. # artifact shared-hosting users upload.
# #
# The verification is not a formality. This script fetches executable code # There is no download and no checksum step, because there is nothing to
# over the network and then runs it as a web server; the checksum is the only # fetch: core is in the repository, already patched, and what you build is
# thing standing between a compromised mirror and every site built from it. # exactly what you can read in `git log wordpress/`. Moving to a new upstream
# If it fails, the build stops — there is no --skip-verify, on purpose. # release is tools/update-wordpress.sh, not a flag here.
set -euo pipefail set -euo pipefail
@ -25,7 +24,7 @@ source tools/wordpress.lock
VERSION="$(grep -m1 "^ \* Version:" plugins/sirius-press-core/sirius-press-core.php | awk '{print $3}')" VERSION="$(grep -m1 "^ \* Version:" plugins/sirius-press-core/sirius-press-core.php | awk '{print $3}')"
DIST="$here/dist" DIST="$here/dist"
TARGET="$DIST/sirius-press" TARGET="$DIST/sirius-press"
CACHE="${SIRIUS_BUILD_CACHE:-$DIST/.cache}" SOURCE="$here/wordpress"
MAKE_ZIP=0 MAKE_ZIP=0
for arg in "$@"; do for arg in "$@"; do
@ -38,67 +37,22 @@ done
say() { printf '\033[1m→\033[0m %s\n' "$*"; } say() { printf '\033[1m→\033[0m %s\n' "$*"; }
die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; } die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }
command -v curl >/dev/null || die "curl is required" [ -f "$SOURCE/wp-includes/version.php" ] \
command -v tar >/dev/null || die "tar is required" || die "wordpress/ is missing or empty — check the whole repository was cloned."
command -v patch >/dev/null || die "patch is required (used to apply the core patch series)"
# ---------------------------------------------------------------- fetch core vendored="$(grep -m1 'wp_version = ' "$SOURCE/wp-includes/version.php" | sed "s/.*'\(.*\)'.*/\1/")"
if [ "$vendored" != "$WP_VERSION" ]; then
mkdir -p "$CACHE" die "wordpress/ holds $vendored but tools/wordpress.lock says $WP_VERSION.
tarball="$CACHE/wordpress-$WP_VERSION.tar.gz" One of them is stale; tools/update-wordpress.sh keeps them in step."
if [ ! -f "$tarball" ]; then
say "downloading WordPress $WP_VERSION"
curl -fsSL -o "$tarball.part" "$WP_URL" || die "download failed"
mv "$tarball.part" "$tarball"
fi fi
say "verifying checksum" # ------------------------------------------------------------------ assemble
actual="$(sha256sum "$tarball" | cut -d' ' -f1)"
if [ "$actual" != "$WP_SHA256" ]; then
rm -f "$tarball"
die "checksum mismatch for WordPress $WP_VERSION
expected $WP_SHA256
got $actual
The cached download has been deleted. If this repeats, the mirror is serving
something other than what this fork was built against — do not work around it."
fi
# --------------------------------------------------------------- assemble say "copying WordPress $vendored out of wordpress/"
say "unpacking into dist/sirius-press"
rm -rf "$TARGET" rm -rf "$TARGET"
mkdir -p "$TARGET" mkdir -p "$TARGET"
tar -xzf "$tarball" -C "$DIST" # The trailing /. copies the contents rather than nesting another directory.
mv "$DIST/wordpress"/* "$TARGET"/ cp -a "$SOURCE/." "$TARGET/"
mv "$DIST/wordpress"/.[!.]* "$TARGET"/ 2>/dev/null || true
rmdir "$DIST/wordpress"
# ------------------------------------------------------------ patch series
shopt -s nullglob
patches=(patches/*.patch)
shopt -u nullglob
if [ ${#patches[@]} -eq 0 ]; then
say "no core patches to apply"
else
say "applying ${#patches[@]} core patch(es)"
for patch in "${patches[@]}"; do
# -F3 tolerates a few lines of drift around the hunk, so a WordPress
# point release that shifts the surrounding code still takes the patch.
# If it genuinely no longer fits, stop: a half-patched installer is
# worse than a failed build.
if (cd "$TARGET" && patch -p1 -F3 --forward --silent < "$here/$patch"); then
echo " ok $(basename "$patch")"
else
die "$(basename "$patch") did not apply to WordPress $WP_VERSION.
Run tools/update-wordpress.sh to refresh the series against this version."
fi
done
fi
# ---------------------------------------------------------------- our code
say "installing Sirius Press plugins" say "installing Sirius Press plugins"
mkdir -p "$TARGET/wp-content/plugins" "$TARGET/wp-content/mu-plugins" mkdir -p "$TARGET/wp-content/plugins" "$TARGET/wp-content/mu-plugins"
@ -107,13 +61,6 @@ for plugin in plugins/*/; do
done done
cp mu-plugins/*.php "$TARGET/wp-content/mu-plugins/" cp mu-plugins/*.php "$TARGET/wp-content/mu-plugins/"
# The stock wp-config-sample.php has no SIRIUS_PRESS_KEY, and a site that
# never sets one falls back to its auth salts — which works, but means
# rotating salts orphans the stored publishing key.
if [ -f docker/wp-config-sirius.php ]; then
cp docker/wp-config-sirius.php "$TARGET/wp-config-sirius-sample.php"
fi
say "built dist/sirius-press ($(du -sh "$TARGET" | cut -f1))" say "built dist/sirius-press ($(du -sh "$TARGET" | cut -f1))"
# --------------------------------------------------------------------- zip # --------------------------------------------------------------------- zip
@ -151,9 +98,9 @@ fi
cat <<EOF cat <<EOF
Sirius Press $VERSION, built on WordPress $WP_VERSION. Sirius Press $VERSION, on WordPress $vendored.
dist/sirius-press/ a complete, patched WordPress tree dist/sirius-press/ a complete tree, ready to serve
$( [ "$MAKE_ZIP" -eq 1 ] && echo " dist/sirius-press-$VERSION.zip upload this to a shared host" ) $( [ "$MAKE_ZIP" -eq 1 ] && echo " dist/sirius-press-$VERSION.zip upload this to a shared host" )
To run it locally: cd docker && docker compose up -d To run it locally: cd docker && docker compose up -d

107
tools/refresh-patches.sh Normal file
View file

@ -0,0 +1,107 @@
#!/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
if diff -rq "$here/patches" "$staging" >/dev/null 2>&1; then
say "patches/ matches the tree"
rm -rf "$staging"
exit 0
fi
diff -ru "$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

View file

@ -1,51 +1,57 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# update-wordpress.sh — move the fork onto a new WordPress release. # update-wordpress.sh — bring a new WordPress release into the fork.
# #
# tools/update-wordpress.sh 7.1.2 # tools/update-wordpress.sh 7.1.2
# tools/update-wordpress.sh 7.1.2 --refresh # also rewrite the patch series
# tools/update-wordpress.sh 7.1.2 --diff wp-admin/install.php
# #
# Fetches the release, verifies it against the SHA-1 wordpress.org publishes, # Two steps, and the second is the one that matters:
# applies the patch series, and reports whether the fork still fits.
# #
# Nothing is committed and tools/wordpress.lock is only rewritten once the # 1. Import the pristine release onto the `sirius-press/wordpress-upstream`
# series has actually applied — so a failed run leaves the fork building the # branch — one commit per version, nothing but upstream, never edited.
# last known-good version rather than a broken one. # 2. `git subtree merge` that branch into wordpress/, which three-way merges
# it against the fork's own commits on top of the last import.
#
# That second step is why core is vendored rather than patched at build time.
# A three-way merge understands that upstream changed lines A and B while the
# fork changed line C, and only stops when they overlap. It also leaves a
# conflict you resolve once, in the file, instead of a patch you re-derive
# every release.
#
# Nothing is pushed. Run it, look at the merge, run the tests, then commit.
set -euo pipefail set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$here" repo="$(git -C "$here" rev-parse --show-toplevel)"
prefix="${here#"$repo"/}/wordpress"
VERSION="${1:-}" VERSION="${1:-}"
REFRESH=0
DIFF_FILE=""
shift || true
while [ $# -gt 0 ]; do
case "$1" in
--refresh) REFRESH=1 ;;
--diff) shift; DIFF_FILE="${1:-}" ;;
*) echo "unknown option: $1" >&2; exit 2 ;;
esac
shift
done
say() { printf '\033[1m→\033[0m %s\n' "$*"; } say() { printf '\033[1m→\033[0m %s\n' "$*"; }
warn() { printf '\033[33mwarning:\033[0m %s\n' "$*" >&2; } warn() { printf '\033[33mwarning:\033[0m %s\n' "$*" >&2; }
die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; } die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; }
[ -n "$VERSION" ] || die "usage: tools/update-wordpress.sh <version> [--refresh] [--diff <file>]" [ -n "$VERSION" ] || die "usage: tools/update-wordpress.sh <version>"
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]] || die "'$VERSION' does not look like a WordPress version" [[ "$VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]] || die "'$VERSION' does not look like a WordPress version"
# shellcheck source=wordpress.lock # shellcheck source=wordpress.lock
source tools/wordpress.lock source "$here/tools/wordpress.lock"
CURRENT="$WP_VERSION" CURRENT="$WP_VERSION"
[ "$VERSION" != "$CURRENT" ] || die "the fork is already on WordPress $VERSION"
UPSTREAM_BRANCH="sirius-press/wordpress-upstream"
git -C "$repo" rev-parse --verify --quiet "$UPSTREAM_BRANCH" >/dev/null \
|| die "the branch $UPSTREAM_BRANCH is missing. It holds the pristine upstream
imports that the subtree merges against; without it this fork cannot take an
upstream release. See docs/upstream-merges.md."
# A subtree merge writes to the working tree, so it has to be clean — at least
# for the paths involved. Refuse early rather than half way through.
if ! git -C "$repo" diff --quiet -- "$prefix" 2>/dev/null; then
die "wordpress/ has uncommitted changes. Commit or stash them first."
fi
WORK="$here/dist/.upstream"
CACHE="$here/dist/.cache" CACHE="$here/dist/.cache"
mkdir -p "$WORK" "$CACHE" mkdir -p "$CACHE"
URL="https://wordpress.org/wordpress-${VERSION}.tar.gz" URL="https://wordpress.org/wordpress-${VERSION}.tar.gz"
TARBALL="$CACHE/wordpress-${VERSION}.tar.gz" TARBALL="$CACHE/wordpress-${VERSION}.tar.gz"
@ -57,155 +63,133 @@ if [ ! -f "$TARBALL" ]; then
mv "$TARBALL.part" "$TARBALL" mv "$TARBALL.part" "$TARBALL"
fi fi
say "verifying against wordpress.org's published SHA-1" say "checking it against the SHA-1 wordpress.org publishes"
published="$(curl -fsSL "${URL}.sha1" 2>/dev/null || true)" published="$(curl -fsSL "${URL}.sha1" 2>/dev/null || true)"
actual_sha1="$(sha1sum "$TARBALL" | cut -d' ' -f1)" actual_sha1="$(sha1sum "$TARBALL" | cut -d' ' -f1)"
if [ -z "$published" ]; then if [ -z "$published" ]; then
warn "wordpress.org did not serve a .sha1 for this release; continuing on the SHA-256 recorded below" warn "wordpress.org served no .sha1 for this release; recording the sha256 below unverified"
elif [ "$published" != "$actual_sha1" ]; then elif [ "$published" != "$actual_sha1" ]; then
rm -f "$TARBALL" rm -f "$TARBALL"
die "SHA-1 mismatch — the download does not match what wordpress.org publishes. die "SHA-1 mismatch — the download is not what wordpress.org publishes.
published $published published $published
got $actual_sha1" got $actual_sha1"
fi fi
NEW_SHA256="$(sha256sum "$TARBALL" | cut -d' ' -f1)" NEW_SHA256="$(sha256sum "$TARBALL" | cut -d' ' -f1)"
# ------------------------------------------------------------------ unpack # ------------------------------------------- import onto the upstream branch
say "unpacking" WORKTREE="$here/dist/.vendor-import"
rm -rf "${WORK:?}/new" "${WORK:?}/pristine" "${WORK:?}/wordpress" say "importing the pristine tree onto $UPSTREAM_BRANCH"
tar -xzf "$TARBALL" -C "$WORK" rm -rf "$WORKTREE"
[ -d "$WORK/wordpress" ] || die "the tarball did not contain a wordpress/ directory" git -C "$repo" worktree add --quiet "$WORKTREE" "$UPSTREAM_BRANCH"
mv "$WORK/wordpress" "$WORK/new"
cp -R "$WORK/new" "$WORK/pristine"
# --------------------------------------------------------- what changed? cleanup() {
git -C "$repo" worktree remove --force "$WORKTREE" >/dev/null 2>&1 || true
}
trap cleanup EXIT
if [ -n "$DIFF_FILE" ]; then # Replace the tree wholesale: files upstream deleted have to disappear, or the
old_tarball="$CACHE/wordpress-${CURRENT}.tar.gz" # subtree merge would keep resurrecting them.
if [ ! -f "$old_tarball" ]; then find "$WORKTREE" -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
say "fetching $CURRENT for comparison" tar -xzf "$TARBALL" -C "$WORKTREE" --strip-components=1
curl -fsSL -o "$old_tarball" "$WP_URL"
fi git -C "$WORKTREE" add -A
rm -rf "$WORK/old" if git -C "$WORKTREE" diff --cached --quiet; then
mkdir -p "$WORK/old" die "WordPress $VERSION is byte-identical to what is already imported."
tar -xzf "$old_tarball" -C "$WORK/old"
say "upstream's own changes to $DIFF_FILE between $CURRENT and $VERSION:"
diff -u "$WORK/old/wordpress/$DIFF_FILE" "$WORK/new/$DIFF_FILE" || true
echo
fi fi
# ------------------------------------------------------------ the series git -C "$WORKTREE" \
-c user.name="Silent Mode" -c user.email="hephaestus@silentmode.st" \
commit -q -m "WordPress ${VERSION}
shopt -s nullglob Pristine upstream, unpacked from the official wordpress.org tarball.
patches=(patches/*.patch)
shopt -u nullglob
failed=0 ${URL}
fuzzed=0 sha1 ${actual_sha1} (published by wordpress.org)
sha256 ${NEW_SHA256}
if [ ${#patches[@]} -eq 0 ]; then This branch carries nothing but upstream releases, one commit each, and is
say "no patches to apply" never edited."
say "imported as $(git -C "$WORKTREE" rev-parse --short HEAD)"
cleanup
trap - EXIT
# ------------------------------------------------------------ subtree merge
say "merging into ${prefix}/"
if git -C "$repo" \
-c user.name="Silent Mode" -c user.email="hephaestus@silentmode.st" \
subtree merge --prefix="$prefix" "$UPSTREAM_BRANCH" \
-m "merge: WordPress ${VERSION} into the vendored subtree"
then
merged=1
else else
say "applying ${#patches[@]} patch(es) to WordPress $VERSION" merged=0
for patch in "${patches[@]}"; do
name="$(basename "$patch")"
output="$(cd "$WORK/new" && patch -p1 -F3 --forward < "$here/$patch" 2>&1)" && rc=0 || rc=$?
if [ "$rc" -ne 0 ]; then
echo " FAILED $name"
echo "$output" | sed 's/^/ /'
failed=1
elif echo "$output" | grep -q 'with fuzz'; then
echo " fuzz $name"
echo "$output" | grep 'with fuzz' | sed 's/^/ /'
fuzzed=1
else
echo " ok $name"
fi
done
fi fi
echo if [ "$merged" -eq 0 ]; then
if [ "$failed" -eq 1 ]; then
cat >&2 <<EOF cat >&2 <<EOF
$(printf '\033[31mThe patch series no longer fits WordPress %s.\033[0m' "$VERSION")
Upstream has rewritten code the fork patches. Nothing has changed here — the $(printf '\033[31mThe merge stopped on a conflict.\033[0m')
lock file still points at $CURRENT and builds still produce a working fork.
Upstream changed code the fork also changes — almost certainly
wp-admin/install.php, the only file this fork patches.
git status # what conflicted
git diff # the overlap
\$EDITOR ${prefix}/wp-admin/install.php
git add ${prefix}/wp-admin/install.php
git commit # finish the merge
Then regenerate the readable copy of the diff and update the lock:
tools/refresh-patches.sh
# set WP_VERSION / WP_URL / WP_SHA256 / WP_SHA1 in tools/wordpress.lock
To fix it:
1. The unpacked tree is at dist/.upstream/new — edit it by hand.
2. Diff it against the pristine copy:
diff -u dist/.upstream/pristine/<file> dist/.upstream/new/<file>
3. Replace the hunks in the failing patch with the result, keeping its
Subject: header and explanation.
4. Run this script again.
EOF EOF
exit 1 exit 1
fi fi
# ------------------------------------------------------------ refresh
if [ "$REFRESH" -eq 1 ]; then
say "regenerating the patch series against $VERSION"
for patch in "${patches[@]}"; do
file="$(grep -m1 '^--- a/' "$patch" | sed 's|^--- a/||')"
[ -n "$file" ] || { warn "$(basename "$patch") has no file header; left alone"; continue; }
header="$(sed -n '1,/^--- a\//p' "$patch" | sed '$d')"
{
echo "$header" | sed "s/^Applies to: WordPress .*/Applies to: WordPress $VERSION/"
diff -u "$WORK/pristine/$file" "$WORK/new/$file" \
| sed -e "1s|.*|--- a/$file|" -e "2s|.*|+++ b/$file|"
} > "$patch.new"
mv "$patch.new" "$patch"
echo " refreshed $(basename "$patch")"
done
elif [ "$fuzzed" -eq 1 ]; then
warn "the series applied with fuzz. Run again with --refresh so the next release starts clean."
fi
# --------------------------------------------------------------- the lock # --------------------------------------------------------------- the lock
say "updating tools/wordpress.lock" say "updating tools/wordpress.lock"
python3 - "$VERSION" "$URL" "$NEW_SHA256" "$actual_sha1" <<'PY' python3 - "$VERSION" "$URL" "$NEW_SHA256" "$actual_sha1" "$here/tools/wordpress.lock" <<'PY'
import io, sys import io, sys
version, url, sha256, sha1 = sys.argv[1:5] version, url, sha256, sha1, path = sys.argv[1:6]
path = 'tools/wordpress.lock' fields = {
'WP_VERSION=': version,
'WP_URL=': url,
'WP_SHA256=': sha256,
'WP_SHA1=': sha1,
}
out = [] out = []
for line in io.open(path, encoding='utf-8'): for line in io.open(path, encoding='utf-8'):
if line.startswith('WP_VERSION='): for key, value in fields.items():
out.append(f'WP_VERSION={version}\n') if line.startswith(key):
elif line.startswith('WP_URL='): line = f'{key}{value}\n'
out.append(f'WP_URL={url}\n') break
elif line.startswith('WP_SHA256='): out.append(line)
out.append(f'WP_SHA256={sha256}\n')
elif line.startswith('WP_SHA1='):
out.append(f'WP_SHA1={sha1}\n')
else:
out.append(line)
io.open(path, 'w', encoding='utf-8', newline='').write(''.join(out)) io.open(path, 'w', encoding='utf-8', newline='').write(''.join(out))
PY PY
# The compose defaults mirror the lock so a plain `docker compose build` if [ -x "$here/tools/refresh-patches.sh" ]; then
# cannot drift onto a different core. say "refreshing patches/ so it still describes the fork's core diff"
sed -i \ "$here/tools/refresh-patches.sh" || warn "could not refresh patches/ — do it by hand"
-e "s|WP_VERSION: \${WP_VERSION:-.*}|WP_VERSION: \${WP_VERSION:-$VERSION}|" \ fi
-e "s|WP_URL: \${WP_URL:-.*}|WP_URL: \${WP_URL:-$URL}|" \
-e "s|WP_SHA256: \${WP_SHA256:-.*}|WP_SHA256: \${WP_SHA256:-$NEW_SHA256}|" \
docker/docker-compose.yml
cat <<EOF cat <<EOF
$(printf '\033[32mSirius Press now builds on WordPress %s.\033[0m' "$VERSION") $(printf '\033[32mSirius Press now builds on WordPress %s.\033[0m' "$VERSION")
tools/wordpress.lock $CURRENT -> $VERSION ${CURRENT} -> ${VERSION}
docker/docker-compose.yml build args updated
The merge and the lock update are staged as commits already; patches/ may
have changed too. Before pushing:
Next:
tests/run.sh tests/run.sh
tools/build.sh tools/build.sh
then walk through wp-admin/install.php once — the setup wizard is the only then walk through wp-admin/install.php once — the setup wizard is the only
patched file, so it is the only thing this can have broken. file this fork patches, so it is the only thing this can have broken.
EOF EOF