Add Svn component: a pure-PHP Subversion client#295
Merged
Conversation
Check out, update, and commit to Subversion repositories over both svn:// (the ra_svn wire protocol) and http(s):// (mod_dav_svn, HTTP protocol v2) without the svn binary or any PHP extension. - Checkouts and updates stream the server's editor drive (single request per operation) with per-file MD5 verification; svndiff0/1 deltas are applied against a pristine store. - svn:externals are checked out as nested working copies, kept in sync on update, and skipped by status/commit. - Conflict-aware updates, status, add/delete/revert/resolved, commits with out-of-date detection, svn:eol-style translation, ANONYMOUS + CRAM-MD5 auth on svn:// and HTTP Basic on http(s)://. Tested against svnserve spawned locally, Apache + mod_dav_svn in Docker, and the live WordPress.org repositories, including a full checkout of wordpress-develop trunk (7078 nodes, checksum-verified, ~46 MB peak memory) and an 80-revision update of real history. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A new
components/Svn/component: a Subversion client in pure PHP. It checks out, updates, and commits to SVN repositories — including WordPress.org's — over bothsvn://(the ra_svn wire protocol) andhttp(s)://(mod_dav_svn), with nosvnbinary and no PHP extensions beyond the toolkit baseline.Why
WordPress lives in Subversion — core development, plugins, and themes all ship through it. Automating anything around that ecosystem from PHP currently means shelling out to a binary most hosted environments don't have. This brings SVN into the same pure-PHP fold as the existing Git component.
How it works
Both transports are implemented around Subversion's core abstraction, the editor drive (a stream of tree-change operations). A checkout or update is one request; the server walks the client through the tree, and file contents arrive as svndiff deltas applied against a local pristine store, MD5-verified per file:
RaSvnSessionspeaks the ra_svn wire protocol: handshake, ANONYMOUS/CRAM-MD5 auth, command tuples, server-driven update editor, client-driven commit editor with svndiff0 windows.DavSessionspeaks HTTP protocol v2 (Subversion 1.7+): OPTIONS stub discovery, PROPFIND/GET reads, streamingupdate-reportREPORT parsing (via the XML component), and commits asPOST create-txn→PUT/MKCOL/DELETE/PROPPATCH→MERGE.SvnWorkingCopy+WorkingCopyEditormanage the working copy: JSON metadata plus a checksum-keyed pristine store under.svn/, status detection,svn:eol-styletranslation, and conflict handling (local file kept, incoming saved as<name>.r<rev>, commit blocked untilresolved()).svn:externals(modern + pre-1.5 syntax,^/..////relative URLs, pinned revisions) are checked out as nested working copies, updated with their parent, and skipped by status/commit — matching the official client.Proof: wordpress-develop
Full checkout of
https://develop.svn.wordpress.org/trunk@ r62480 withmemory_limit=512M:svn ls -Rsvn cat; every file MD5-verified during the drive; fullstatuswalk cleantests/phpunit/data/plugins/wordpress-importer(a cross-server external to plugins.svn.wordpress.org) checked out automaticallyReproducible via
SVN_TESTS_ONLINE=1 SVN_TESTS_HUGE=1 vendor/bin/phpunit components/Svn/Tests/WordPressDevelopCheckoutTest.php.Tests
All scenarios run against real SVN servers, never mocks:
SvnserveClientTestspawnssvnadmin-created repositories behind a realsvnserve(auto-skips without the binaries). Includes an interop test: working copies byte-identical with the official client's, commits visible in both directions.DavClientTestruns Apache + mod_dav_svn in Docker (Tests/http-server/, auto-skips without Docker), anonymous and Basic-auth repositories.SvnClientBehaviorTrait: checkout (incl. depth + old revisions), status, commit roundtrips, updates, conflict/resolve flows, revert, forced deletes, out-of-date rejection, auth failure/success, externals.WordPressOrgTest(gated bySVN_TESTS_ONLINE=1) exercises develop.svn.wordpress.org and plugins.svn.wordpress.org.composer lintclean for the component; PHPCompatibility clean for 7.2; full project suite passes (5600 tests).Design notes & limitations
.svn/wc.json+ pristine store), not the official client's SQLitewc.db. Repositories interoperate fully; working copies don't transfer between clients.svn:eol-stylevalues (CRLF/CR/LF) the repository itself stores that line ending — normalizing to LF made fresh checkouts look locally modified and could silently commit eol rewrites. There's a regression test (test_commit_does_not_rewrite_eol_styled_files).@TODOs for the XML component surfaced here: it can't pause mid-XML-declaration in streaming mode (worked around with a tiny prelude buffer) and its 1 GiB memory budget isn't publicly configurable (worked around with a guarded reflection tweak; that's what keeps 600 MB checkouts at ~40 MB RAM).file://,svn+ssh://, locks,svn:keywords,svn:specialsymlinks, merge tracking, mixed-depth sparse checkouts. Documented in the README.composer.jsonwas edited by hand (classmap + files) —bin/regenerate_composer.json.phpmentioned in AGENTS.md doesn't exist in the repo.