Skip to content

Commit

Permalink
Boot: Move WordPress zip extraction logic to a common unzipWordPress(…
Browse files Browse the repository at this point in the history
…) utility (#1427)

Moves the WordPress.zip extraction logic to a common utility function
called `unzipWordPress` and living in the `@wp-playground/wordpress`
package. This allows both `remote.html` and Playground CI to boot
consistently.

This and #1425 unlocks providing WordPress ZIP bundles in Blueprints via
`{ "preferredVersion": { "wp": "<URL>" } }`.

## Implementation details and follow-up work

The goal of `unzipWordPress()` is to extract a zipped WordPress
installation at a specified location in VFS. This isn't a trivial task
as WordPress might exist at a root of the zip file, at a nested
`/wordpress` directory, in another `wordpress.zip` file living inside
the initial `wp.zip` archive, or in any subdirectory of the above. The
current implementation covers a few basic cases, but nothing beyond
that.

Looking forward, we should:

* Move that logic to the [PHP Blueprints
library](https://github.com/WordPress/blueprints-library/)
* Either:
* Make it "just work", e.g. by traversing nested zips and directories in
search for WordPress
* Don't guess anything and allow the developer to specify the exact
"coordinates" of their zipped WordPress
* Only accept a few variations, throw an error when an unsupported zip
is provided, document it thoroughly and provide a very informative error
message

## Testing instructions

Confirm the E2E tests pass
  • Loading branch information
adamziel authored May 20, 2024
1 parent b7dac82 commit 33249d7
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 43 deletions.
39 changes: 5 additions & 34 deletions packages/playground/cli/src/setup-wp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import {
CACHE_FOLDER,
readAsFile,
} from './download';
import { preloadSqliteIntegration } from '@wp-playground/wordpress';
import { withPHPIniValues } from '@php-wasm/universal';
import {
preloadSqliteIntegration,
unzipWordPress,
} from '@wp-playground/wordpress';

/**
* Ensures a functional WordPress installation in php document root.
Expand Down Expand Up @@ -49,7 +52,7 @@ export async function setupWordPress(
monitor
),
]);
await prepareWordPress(php, wpZip);
await unzipWordPress(php, wpZip);
// Setup the SQLite integration if no custom database drop-in is present
if (!php.fileExists('/wordpress/wp-content/db.php')) {
await preloadSqliteIntegration(php, sqliteZip);
Expand Down Expand Up @@ -93,35 +96,3 @@ export async function setupWordPress(
fs.writeFileSync(preinstalledWpContentPath, wpContent);
}
}

/**
* Prepare the WordPress document root given a WordPress zip file and
* the sqlite-database-integration zip file.
*
* This is a TypeScript function for now, just to get something off the
* ground, but it may be superseded by the PHP Blueprints library developed
* at https://github.com/WordPress/blueprints-library/
*
* That PHP library will come with a set of functions and a CLI tool to
* turn a Blueprint into a WordPress directory structure or a zip Snapshot.
* Let's **not** invest in the TypeScript implementation of this function,
* accept the limitation, and switch to the PHP implementation as soon
* as that's viable.
*/
async function prepareWordPress(php: NodePHP, wpZip: File) {
php.mkdir('/tmp/unzipped-wordpress');
await unzip(php, {
zipFile: wpZip,
extractToPath: '/tmp/unzipped-wordpress',
});
// The zip file may contain a subdirectory, or not.
const wpPath = php.fileExists('/tmp/unzipped-wordpress/wordpress')
? '/tmp/unzipped-wordpress/wordpress'
: '/tmp/unzipped-wordpress';

php.mv(wpPath, '/wordpress');
php.writeFile(
'/wp-config.php',
php.readFileAsText('/wordpress/wp-config-sample.php')
);
}
13 changes: 5 additions & 8 deletions packages/playground/remote/src/lib/worker-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
sqliteDatabaseIntegration,
} from '@wp-playground/wordpress-builds';
import {
unzipWordPress,
preloadSqliteIntegration,
wordPressRewriteRules,
} from '@wp-playground/wordpress';
Expand All @@ -22,7 +23,6 @@ import {
defineSiteUrl,
defineWpConfigConsts,
runWpInstallationWizard,
unzip,
} from '@wp-playground/blueprints';

import { randomString } from '@php-wasm/util';
Expand Down Expand Up @@ -189,13 +189,10 @@ try {
// If WordPress isn't already installed, download and extract it from
// the zip file.
if (!wordPressAvailableInOPFS) {
await unzip(primaryPhp, {
zipFile: new File(
[await (await wordPressRequest!).blob()],
'wp.zip'
),
extractToPath: requestHandler.documentRoot,
});
await unzipWordPress(
primaryPhp,
new File([await (await wordPressRequest!).blob()], 'wp.zip')
);

// Randomize the WordPress secrets
await defineWpConfigConsts(primaryPhp, {
Expand Down
49 changes: 48 additions & 1 deletion packages/playground/wordpress/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UniversalPHP } from '@php-wasm/universal';
import { BasePHP, UniversalPHP } from '@php-wasm/universal';
import { joinPaths, phpVar } from '@php-wasm/util';
import { unzipFile } from '@wp-playground/common';

Expand Down Expand Up @@ -295,3 +295,50 @@ if(!function_exists('mysqli_connect')) {
`
);
}

/**
* Prepare the WordPress document root given a WordPress zip file and
* the sqlite-database-integration zip file.
*
* This is a TypeScript function for now, just to get something off the
* ground, but it may be superseded by the PHP Blueprints library developed
* at https://github.com/WordPress/blueprints-library/
*
* That PHP library will come with a set of functions and a CLI tool to
* turn a Blueprint into a WordPress directory structure or a zip Snapshot.
* Let's **not** invest in the TypeScript implementation of this function,
* accept the limitation, and switch to the PHP implementation as soon
* as that's viable.
*/
export async function unzipWordPress(php: BasePHP, wpZip: File) {
php.mkdir('/tmp/unzipped-wordpress');
await unzipFile(php, wpZip, '/tmp/unzipped-wordpress');

// The zip file may contain another zip file if it's coming from GitHub artifacts
// @TODO: Don't make so many guesses about the zip file contents. Allow the
// API consumer to specify the exact "coordinates" of WordPress inside
// the zip archive.
if (php.fileExists('/tmp/unzipped-wordpress/wordpress.zip')) {
await unzipFile(
php,
'/tmp/unzipped-wordpress/wordpress.zip',
'/tmp/unzipped-wordpress'
);
}

// The zip file may contain a subdirectory, or not.
// @TODO: Don't make so many guesses about the zip file contents. Allow the
// API consumer to specify the exact "coordinates" of WordPress inside
// the zip archive.
const wpPath = php.fileExists('/tmp/unzipped-wordpress/wordpress')
? '/tmp/unzipped-wordpress/wordpress'
: php.fileExists('/tmp/unzipped-wordpress/build')
? '/tmp/unzipped-wordpress/build'
: '/tmp/unzipped-wordpress';

php.mv(wpPath, php.documentRoot);
php.writeFile(
'/wp-config.php',
php.readFileAsText(php.documentRoot + '/wp-config-sample.php')
);
}

0 comments on commit 33249d7

Please sign in to comment.