Skip to content

Snapshot Import Protocol v1#1007

Closed
adamziel wants to merge 6 commits into
trunkfrom
ensure-sqlite-integration-plugin
Closed

Snapshot Import Protocol v1#1007
adamziel wants to merge 6 commits into
trunkfrom
ensure-sqlite-integration-plugin

Conversation

@adamziel
Copy link
Copy Markdown
Collaborator

@adamziel adamziel commented Feb 6, 2024

What is this PR doing?

🚧 This is still work in progress as I'm not sure about the setSnapshot vs linkSnapshot semantics. 🚧

Consolidates site setup code paths between the web worker and the import step. With this PR, both support:

  • A Playground export with just wp-config.php and wp-content inside
  • A Playground export that also bundles WordPress core
  • A vanilla WordPress build downloaded from WordPress.org
  • A WordPress PR build from GitHub CI

This means the same file format can be passed to ?wp=https://mysite.com/wp.zip Query Parameter, {"preferredVersions": { "wp": "https://mysite.com/wp.zip" } } Blueprint config, and the importWordPressFiles Blueprint step. I'd like to rename the latter to importSnapshot.

I'd like this PR to be the first iteration of the Site Transfer Protocol in Playground. For now, it's built in JS. Eventually, it could be built in PHP.

Implementation details

With this PR, setting up a Playground snapshot works as follows.

"Setting the snapshot" stage:

  1. Unzip the snapshot to .snapshot
  2. If WordPress core files are missing, backfill them
  3. If wp-config.php is missing, backfill it
  4. If the SQLite plugin is missing, backfill it
  5. Replace the contents of document root with the contents of .snapshot

"Linking" stage:

  1. Activate the SQLite plugin
  2. Activate the Playground mu-plugin (by creating its files)
  3. Set the site URL constants
  4. Set random secrets
  5. Run the installation wizard if the database file is missing

The distinction is not as crisp as I'd like. My main intention was to harmonize this initialization code path in worker-thread.ts where the snapshot may be a fresh zip we're only setting up now, but it may also be a local directory with either vanilla WordPress or fully set-up Playground:

	// If WordPress isn't already installed, download and extract it from
	// the zip file.
	if (!wordPressAvailableInOPFS) {
		const snapshot = new File(
			[await (await wordPressRequest!).blob()],
			'wp.zip'
		);
		await setSnapshot(php, snapshot);
	}

	// We always need the SQLite mu-plugin in the browser.
	await backfillSqliteMuPlugin(php, docroot);
	await linkSnapshot(php);

cc @dmsnell @bgrgicak

* the corresponding directories in Playground's documentRoot.
*
* Any files that Playground recognizes as "excluded from the export"
* Any files that Playground recognizes as "exceptd from the export"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Any files that Playground recognizes as "exceptd from the export"
* Any files that Playground recognizes as "excepted from the export"

@bgrgicak
Copy link
Copy Markdown
Collaborator

bgrgicak commented Feb 7, 2024

I'm not sure about the setSnapshot vs linkSnapshot semantics.

@adamziel what are you unsure about here?

@adamziel
Copy link
Copy Markdown
Collaborator Author

adamziel commented Feb 7, 2024

I just had an epiphany. It doesn't make sense to have an import site Blueprint step:

  • It makes no sense to run some steps only to discard them and replace the entire site
  • Generalizing the setup logic makes it more complex without adding clear value
  • WordPress version can already be specified as a URL

I'll rework this PR to remove that step and put the WordPress initialization logic in playground-remote.

I'm not sure about the setSnapshot vs linkSnapshot semantics.

@adamziel what are you unsure about here?

I struggled to draw clear boundaries that would make logic general and reusable in wp-now. I no longer think doing that makes sense. wp-now caches the downloads, uses local mounts, and infers a "mode" (wp-content, plugin, theme, etc). Let's allow both tools do what they need for initialization, and only extract a common abstraction when either there's a need for that or when one naturally emerges.

@adamziel
Copy link
Copy Markdown
Collaborator Author

adamziel commented Feb 9, 2024

This is more complex than I initially imagined.

  • A Snapshot may contain either wp-content and wp-config.php or an entire WordPress installation
  • The filesystem may be either clean (new MEMFS) or already populated (OPFS pointing to a local directory)
  • ZIP import UI works without a page reload and applies the uploaded Snapshot on top of the current VFS state

Let's imagine we have just wp-content + empty FS. We need to unzip it and then, backfill WordPress core. Which WP version? Let's assume the latest one for now.
* We won't know for sure until the Snapshot includes a JSON file listing the required WP core version.
* We'll only be able to start downloading WordPress core once we read that JSON. This means downloading the snapshot, unzipping, reading and issuing another request only then. Once the Stream Processing API matures, we should be able to stream-read that version number upfront.

A list of cases to consider:

  • Just wp-content + empty FS -> Unzip, backfill WordPress core.
  • Just wp-content + populated FS -> Wipe out the FS, unzip, backfill WordPress core. OR throw an exception.
  • Full WordPress + empty FS -> Unzip.
  • Full WordPress + populated FS -> Wipe out the FS, unzip. OR throw an exception.

I'm leaning towards just giving up if the FS is already populated. Let the user make an explicit choice. Hey, you're about to overwrite some files, are you sure about that? If yes, the API consumer would remove all the files in the document root and resume.

@adamziel
Copy link
Copy Markdown
Collaborator Author

adamziel commented Feb 9, 2024

One more plot-twist – the OPFS root may be inside the wp-content folder. Let's not handle that for now. This will require larger explorations to converge with wp-now and expose an API that can serve both Playground web and wp-now.

@adamziel adamziel requested a review from a team as a code owner February 9, 2024 15:16
@bgrgicak
Copy link
Copy Markdown
Collaborator

I'm leaning towards just giving up if the FS is already populated. Let the user make an explicit choice. Hey, you're about to overwrite some files, are you sure about that? If yes, the API consumer would remove all the files in the document root and resume.

That makes sense, we shouldn't rewrite the FS without users knowing.

Otherwise, we can just delete everything and start building from scratch to keep the implementation simple.

We won't know for sure until the Snapshot includes a JSON file listing the required WP core version.

When we add support for blueprint exports to PHP, let's add the blueprint.json file to the ZIP export in the Playground plugin.

@adamziel
Copy link
Copy Markdown
Collaborator Author

adamziel commented Mar 4, 2024

I no longer think this problem should be solved in TypeScript. Let's explore a canonical PHP implementation in the new Blueprints repository and use it to inform the work on the site transfer protocol.

@adamziel adamziel closed this Mar 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants