Skip to content

Commit

Permalink
Install the SQLite integration plugin in worker-thread.ts, run WordPr…
Browse files Browse the repository at this point in the history
…ess installer if needed
  • Loading branch information
adamziel committed May 17, 2024
1 parent 2a8e2d9 commit 5ebce24
Show file tree
Hide file tree
Showing 125 changed files with 202 additions and 6,117 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/refresh-wordpress-major-and-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ jobs:
clean: true
persist-credentials: false
- uses: ./.github/actions/prepare-playground
- name: 'Install bun (for the changelog)'
run: |
curl -fsSL https://bun.sh/install | bash
- name: 'Recompile WordPress'
shell: bash
env:
FORCE_REBUILD: ${{ github.event.inputs.force_rebuild }}
run: npx nx bundle-wordpress:major-and-beta playground-wordpress-builds
run: PATH="${PATH}:${HOME}/.bun/bin" npx nx bundle-wordpress:major-and-beta playground-wordpress-builds
- name: Check for uncommitted changes
id: changes
run: |
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/refresh-wordpress-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@ jobs:
clean: true
persist-credentials: false
- uses: ./.github/actions/prepare-playground
- name: 'Install bun (for the changelog)'
run: |
curl -fsSL https://bun.sh/install | bash
- name: 'Recompile WordPress'
shell: bash
run: npx nx bundle-wordpress:nightly playground-wordpress-builds
env:
FORCE_REBUILD: ${{ github.event.inputs.force_rebuild }}
run: PATH="${PATH}:${HOME}/.bun/bin" npx nx bundle-wordpress:nightly playground-wordpress-builds
- name: Config git user
run: |
git config --global user.name "deployment_bot"
Expand Down
6 changes: 5 additions & 1 deletion packages/php-wasm/universal/src/lib/base-php.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,11 @@ export abstract class BasePHP implements IsomorphicLocalPHP, Disposable {
heapBodyPointer = this.#setRequestBody(request.body);
}
if (typeof request.code === 'string') {
this.#setPHPCode(' ?>' + request.code);
// @TODO: prepend the auto_prepend_file even when running code and not a file
this.#setPHPCode(
' ?><?php require_once "/internal/shared/auto_prepend_file.php"; ?>' +
request.code
);
}

const $_SERVER = this.#prepareServerEntries(
Expand Down
40 changes: 0 additions & 40 deletions packages/playground/cli/src/setup-php.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
rotatePHPRuntime,
} from '@php-wasm/universal';
import { rootCertificates } from 'tls';
import { dirname } from '@php-wasm/util';
import {
preloadPhpInfoRoute,
enablePlatformMuPlugins,
Expand Down Expand Up @@ -75,42 +74,3 @@ export async function createPhp(
});
return php;
}

/**
* @TODO: Ship this feature in the php-wasm library.
*
* Perhaps change the implementation of the setPhpIniValue()?
* We could ensure there's always a valid php.ini file,
* even if empty. php_wasm.c wouldn't provide any defaults.
* BasePHP would, and it would write them to the default php.ini
* file. Then we'd be able to use setPhpIniValue() at any time, not
* just before the first run() call.
*/
export async function withPHPIniValues(
php: NodePHP,
phpIniValues: Record<string, string>,
callback: () => Promise<void>
) {
const phpIniPath = (
await php.run({
code: '<?php echo php_ini_loaded_file();',
})
).text;
const phpIniDir = dirname(phpIniPath);
if (!php.fileExists(phpIniDir)) {
php.mkdir(phpIniDir);
}
if (!php.fileExists(phpIniPath)) {
php.writeFile(phpIniPath, '');
}
const originalPhpIni = php.readFileAsText(phpIniPath);
const newPhpIni = Object.entries(phpIniValues)
.map(([key, value]) => `${key} = ${value}`)
.join('\n');
php.writeFile(phpIniPath, [originalPhpIni, newPhpIni].join('\n'));
try {
await callback();
} finally {
php.writeFile(phpIniPath, originalPhpIni);
}
}
41 changes: 6 additions & 35 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 { withPHPIniValues } from './setup-php';
import { preloadSqliteIntegration } from '@wp-playground/wordpress';
import {
preloadSqliteIntegration,
unzipWordPress,
withPHPIniValues,
} 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 @@ -94,35 +97,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')
);
}
72 changes: 62 additions & 10 deletions packages/playground/remote/src/lib/worker-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ import { DOCROOT, wordPressSiteUrl } from './config';
import {
getWordPressModuleDetails,
LatestSupportedWordPressVersion,
sqliteIntegrationUrl,
SupportedWordPressVersions,
} from '@wp-playground/wordpress-builds';
import { wordPressRewriteRules } from '@wp-playground/wordpress';
import {
preloadSqliteIntegration,
unzipWordPress,
withPHPIniValues,
wordPressRewriteRules,
} from '@wp-playground/wordpress';
import { PHPRequestHandler } from '@php-wasm/universal';
import {
SyncProgressCallback,
Expand All @@ -17,7 +23,7 @@ import {
import {
defineSiteUrl,
defineWpConfigConsts,
unzip,
runWpInstallationWizard,
} from '@wp-playground/blueprints';

import { randomString } from '@php-wasm/util';
Expand Down Expand Up @@ -59,8 +65,14 @@ if (

// Start downloading WordPress if needed
let wordPressRequest = null;
let sqliteIntegrationRequest = null;
if (!wordPressAvailableInOPFS) {
if (requestedWPVersion.startsWith('http')) {
sqliteIntegrationRequest = monitoredFetch(sqliteIntegrationUrl);
if (
requestedWPVersion.startsWith('http://') ||
requestedWPVersion.startsWith('https://') ||
requestedWPVersion.startsWith('/plugin-proxy.php')
) {
// We don't know the size upfront, but we can still monitor the download.
// monitorFetch will read the content-length response header when available.
wordPressRequest = monitoredFetch(requestedWPVersion);
Expand Down Expand Up @@ -176,13 +188,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 Expand Up @@ -210,6 +219,49 @@ try {
});
}

// Setup the SQLite integration if no custom database drop-in is present
if (
!primaryPhp.fileExists(primaryPhp.documentRoot + '/wp-content/db.php')
) {
const sqliteIntegrationZip = await (
await sqliteIntegrationRequest
)?.blob();
if (sqliteIntegrationZip) {
await preloadSqliteIntegration(
primaryPhp,
new File([sqliteIntegrationZip], 'sqlite.zip')
);
}
}

// Install WordPress if it isn't installed yet
const isInstalled =
(
await primaryPhp.run({
code: `<?php
require '${primaryPhp.documentRoot}/wp-load.php';
echo is_blog_installed() ? '1' : '0';
`,
})
).text === '1';
if (!isInstalled) {
// Disable networking for the installation wizard
// to avoid loopback requests and also speed it up.
// @TODO: Expose withPHPIniValues as a function from the
// php-wasm library.
await withPHPIniValues(
primaryPhp,
{
disable_functions: 'fsockopen',
allow_url_fopen: '0',
},
async () =>
await runWpInstallationWizard(primaryPhp, {
options: {},
})
);
}

// Always setup the current site URL.
await defineSiteUrl(primaryPhp, {
siteUrl: scopedSiteUrl,
Expand Down
2 changes: 2 additions & 0 deletions packages/playground/remote/src/lib/worker-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,12 @@ export async function createPhp(
if (startupOptions.sapiName) {
await php.setSapiName(startupOptions.sapiName);
}
php.setPhpIniPath('/internal/shared/php.ini');
php.setPhpIniEntry('memory_limit', '256M');
php.setSpawnHandler(spawnHandlerFactory(requestHandler.processManager));

if (isPrimary) {
php.writeFile('/internal/shared/php.ini', '');
const scopedSitePath = new URL(siteUrl).pathname;
await preloadPhpInfoRoute(
php,
Expand Down
63 changes: 5 additions & 58 deletions packages/playground/website/public/wordpress.html
Original file line number Diff line number Diff line change
Expand Up @@ -204,65 +204,12 @@
const blueprint = {
$schema:
'https://playground.wordpress.net/blueprint-schema.json',
login: true,
landingPage: urlParams.get('url') || '/wp-admin',
steps: [
{
step: 'mkdir',
path: '/wordpress-new',
},
/*
* Download WordPress build from a given GitHub PR.
*
* Because the zip file is not publicly accessible, we use the
* plugin-proxy API endpoint to download it. The source code of
* that endpoint is available at:
* https://github.com/WordPress/wordpress-playground/blob/trunk/packages/playground/website/public/plugin-proxy.php
*/
{
step: 'writeFile',
path: '/tmp/pr.zip',
data: {
resource: 'url',
url: zipArtifactUrl,
caption: `Downloading WordPress PR ${prNumber}`,
},
},
// Extract and remove the zip file.
{
step: 'unzip',
zipPath: '/tmp/pr.zip',
extractToPath: '/tmp',
},
{
step: 'rm',
path: '/tmp/pr.zip',
},
// Import the unzipped PR.
{
step: 'importWordPressFiles',
wordPressFilesZip: {
resource: 'vfs',
path: '/tmp/wordpress.zip',
},
pathInZip: '/build',
progress: {
weight: 20,
caption: `Applying WordPress PR ${prNumber}`,
},
},
{
step: 'runPHP',
code: `<?php
$_GET['step'] = 'upgrade_db';
require '/wordpress/wp-admin/upgrade.php';
`,
},
{
step: 'login',
username: 'admin',
password: 'password',
},
],
preferredVersions: {
wp: zipArtifactUrl,
php: '7.4',
},
};
const encoded = JSON.stringify(blueprint);

Expand Down
7 changes: 7 additions & 0 deletions packages/playground/wordpress-builds/build/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ const sourceDir = path.dirname(new URL(import.meta.url).pathname);
const outputAssetsDir = path.resolve(process.cwd(), args.outputAssets);
const outputJsDir = path.resolve(process.cwd(), args.outputJs);

// @TODO: Put this in a separate script and set up nx, npm, and GitHub Actions to run it
// Refresh sqlite-database-integration.zip
const outputZipPath = `${outputJsDir}/sqlite-database-integration.zip`;
const sqliteResponse = await fetch('https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/main.zip');
const sqliteZip = Buffer.from(await sqliteResponse.arrayBuffer());
await fs.writeFile(outputZipPath, sqliteZip);

// Short-circuit if the version is already downloaded and not forced
const versionsPath = `${outputJsDir}/wp-versions.json`;
let versions = {};
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DENY FROM ALL
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 5ebce24

Please sign in to comment.