From 84ef2c79dabcb7c4b3843b8ac9cffb7cdeee5b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Tue, 18 Jun 2024 10:42:38 +0200 Subject: [PATCH 1/2] Source WordPress zip from a local cache file before looking for it online --- packages/playground/cli/src/cli.ts | 87 +++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/packages/playground/cli/src/cli.ts b/packages/playground/cli/src/cli.ts index 4727d23b56..463943b7e9 100644 --- a/packages/playground/cli/src/cli.ts +++ b/packages/playground/cli/src/cli.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import path from 'path'; import yargs from 'yargs'; +import { globSync } from 'glob'; import { startServer } from './server'; import { PHP, @@ -272,24 +273,14 @@ async function run() { } }) as any); - wpDetails = await resolveWPRelease(args.wp); + wpDetails = await resolveWordPressZip(args.wp, monitor); } - const preinstalledWpContentPath = path.join( - CACHE_FOLDER, - `prebuilt-wp-content-for-wp-${wpDetails.version}.zip` - ); - const wordPressZip = !wpDetails - ? undefined - : fs.existsSync(preinstalledWpContentPath) - ? readAsFile(preinstalledWpContentPath) - : fetchWordPress(wpDetails.url, monitor); - requestHandler = await bootWordPress({ siteUrl: absoluteUrl, createPhpRuntime: async () => await loadNodeRuntime(compiledBlueprint.versions.php), - wordPressZip, + wordPressZip: wpDetails.zipFile, sqliteIntegrationPluginZip: fetchSqliteIntegration(monitor), sapiName: 'cli', createFiles: { @@ -313,8 +304,8 @@ async function run() { const php = await requestHandler.getPrimaryPhp(); if (wpDetails && !args.mountBeforeInstall) { fs.writeFileSync( - preinstalledWpContentPath, - await zipDirectory(php, '/wordpress') + wpDetails.localZipPath, + await zipDirectory(php, requestHandler.documentRoot) ); } @@ -359,4 +350,72 @@ async function run() { }); } +async function resolveWordPressZip( + preferredVersion: string, + monitor: EmscriptenDownloadMonitor +): Promise<{ zipFile: File | Promise; localZipPath: string }> { + const filenamePrefix = `prebuilt-wp-`; + const filenameSuffix = `.zip`; + let wpDetails; + + // First, let's grab a pre-installed WordPress zip file we may have + // already prepared earlier. + const localVersions = globSync( + path.join(CACHE_FOLDER, `${filenamePrefix}*${filenameSuffix}`) + ) + .sort() + .map((path) => path.split('/').pop()!) + .reverse(); + let resolvedFilename: string | undefined; + if (preferredVersion === 'latest') { + resolvedFilename = localVersions.filter( + (filename) => + !filename.includes('beta') && !filename.includes('nightly') + )[0]; + } else if (preferredVersion === 'beta') { + resolvedFilename = localVersions.filter((filename) => + filename.includes('beta') + )[0]; + } else if (preferredVersion === 'nightly') { + resolvedFilename = localVersions.filter((filename) => + filename.includes('nightly') + )[0]; + } else { + resolvedFilename = localVersions.filter((filename) => + filename.startsWith(`${filenamePrefix}${preferredVersion}`) + )[0]; + } + if (resolvedFilename) { + const localZipPath = path.join(CACHE_FOLDER, resolvedFilename); + const zipFile = readAsFile(localZipPath); + return { + zipFile, + localZipPath, + }; + } + + // We don't have this WordPress version on the device. Let's + // do a network lookup. + try { + wpDetails = await resolveWPRelease(preferredVersion); + const localZipPath = path.join( + CACHE_FOLDER, + `${filenamePrefix}${wpDetails.version}${filenameSuffix}` + ); + return { + zipFile: fs.existsSync(localZipPath) + ? readAsFile(localZipPath) + : fetchWordPress(wpDetails.url, monitor), + localZipPath, + }; + } catch (e) { + throw new Error( + `Could not resolve WordPress ${resolvedFilename} from local cache (you're offline)`, + { + cause: e, + } + ); + } +} + run(); From 6d0b11c8dc584e16e5b8d6ddb34035e759ae0221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Tue, 18 Jun 2024 10:46:06 +0200 Subject: [PATCH 2/2] Move resolveWordPressZip to download.ts --- packages/playground/cli/src/cli.ts | 77 +----------------------- packages/playground/cli/src/download.ts | 78 +++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/packages/playground/cli/src/cli.ts b/packages/playground/cli/src/cli.ts index 463943b7e9..61bed13b9f 100644 --- a/packages/playground/cli/src/cli.ts +++ b/packages/playground/cli/src/cli.ts @@ -1,7 +1,6 @@ import fs from 'fs'; import path from 'path'; import yargs from 'yargs'; -import { globSync } from 'glob'; import { startServer } from './server'; import { PHP, @@ -23,13 +22,7 @@ import { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node'; import { RecommendedPHPVersion, zipDirectory } from '@wp-playground/common'; import { bootWordPress } from '@wp-playground/wordpress'; import { rootCertificates } from 'tls'; -import { - CACHE_FOLDER, - fetchSqliteIntegration, - fetchWordPress, - readAsFile, - resolveWPRelease, -} from './download'; +import { resolveWordPressZip, fetchSqliteIntegration } from './download'; export interface Mount { hostPath: string; @@ -350,72 +343,4 @@ async function run() { }); } -async function resolveWordPressZip( - preferredVersion: string, - monitor: EmscriptenDownloadMonitor -): Promise<{ zipFile: File | Promise; localZipPath: string }> { - const filenamePrefix = `prebuilt-wp-`; - const filenameSuffix = `.zip`; - let wpDetails; - - // First, let's grab a pre-installed WordPress zip file we may have - // already prepared earlier. - const localVersions = globSync( - path.join(CACHE_FOLDER, `${filenamePrefix}*${filenameSuffix}`) - ) - .sort() - .map((path) => path.split('/').pop()!) - .reverse(); - let resolvedFilename: string | undefined; - if (preferredVersion === 'latest') { - resolvedFilename = localVersions.filter( - (filename) => - !filename.includes('beta') && !filename.includes('nightly') - )[0]; - } else if (preferredVersion === 'beta') { - resolvedFilename = localVersions.filter((filename) => - filename.includes('beta') - )[0]; - } else if (preferredVersion === 'nightly') { - resolvedFilename = localVersions.filter((filename) => - filename.includes('nightly') - )[0]; - } else { - resolvedFilename = localVersions.filter((filename) => - filename.startsWith(`${filenamePrefix}${preferredVersion}`) - )[0]; - } - if (resolvedFilename) { - const localZipPath = path.join(CACHE_FOLDER, resolvedFilename); - const zipFile = readAsFile(localZipPath); - return { - zipFile, - localZipPath, - }; - } - - // We don't have this WordPress version on the device. Let's - // do a network lookup. - try { - wpDetails = await resolveWPRelease(preferredVersion); - const localZipPath = path.join( - CACHE_FOLDER, - `${filenamePrefix}${wpDetails.version}${filenameSuffix}` - ); - return { - zipFile: fs.existsSync(localZipPath) - ? readAsFile(localZipPath) - : fetchWordPress(wpDetails.url, monitor), - localZipPath, - }; - } catch (e) { - throw new Error( - `Could not resolve WordPress ${resolvedFilename} from local cache (you're offline)`, - { - cause: e, - } - ); - } -} - run(); diff --git a/packages/playground/cli/src/download.ts b/packages/playground/cli/src/download.ts index 1eae2589ba..152fd47b29 100644 --- a/packages/playground/cli/src/download.ts +++ b/packages/playground/cli/src/download.ts @@ -2,6 +2,7 @@ import { EmscriptenDownloadMonitor } from '@php-wasm/progress'; import { createHash } from 'crypto'; import fs from 'fs-extra'; import os from 'os'; +import { globSync } from 'glob'; import path, { basename } from 'path'; export const CACHE_FOLDER = path.join(os.homedir(), '.wordpress-playground'); @@ -84,6 +85,83 @@ export function readAsFile(path: string, fileName?: string): File { return new File([fs.readFileSync(path)], fileName ?? basename(path)); } +/** + * Offline-first WordPress zip resolution. + * It will first look for a pre-installed WordPress zip file in the local cache, + * and will only do a network lookup if it doesn't find one. + * + * @param preferredVersion + * @param monitor + * @returns + */ +export async function resolveWordPressZip( + preferredVersion: string, + monitor: EmscriptenDownloadMonitor +): Promise<{ zipFile: File | Promise; localZipPath: string }> { + const filenamePrefix = `prebuilt-wp-`; + const filenameSuffix = `.zip`; + let wpDetails; + + // First, let's grab a pre-installed WordPress zip file we may have + // already prepared earlier. + const localVersions = globSync( + path.join(CACHE_FOLDER, `${filenamePrefix}*${filenameSuffix}`) + ) + .sort() + .map((path) => path.split('/').pop()!) + .reverse(); + let resolvedFilename: string | undefined; + if (preferredVersion === 'latest') { + resolvedFilename = localVersions.filter( + (filename) => + !filename.includes('beta') && !filename.includes('nightly') + )[0]; + } else if (preferredVersion === 'beta') { + resolvedFilename = localVersions.filter((filename) => + filename.includes('beta') + )[0]; + } else if (preferredVersion === 'nightly') { + resolvedFilename = localVersions.filter((filename) => + filename.includes('nightly') + )[0]; + } else { + resolvedFilename = localVersions.filter((filename) => + filename.startsWith(`${filenamePrefix}${preferredVersion}`) + )[0]; + } + if (resolvedFilename) { + const localZipPath = path.join(CACHE_FOLDER, resolvedFilename); + const zipFile = readAsFile(localZipPath); + return { + zipFile, + localZipPath, + }; + } + + // We don't have this WordPress version on the device. Let's + // do a network lookup. + try { + wpDetails = await resolveWPRelease(preferredVersion); + const localZipPath = path.join( + CACHE_FOLDER, + `${filenamePrefix}${wpDetails.version}${filenameSuffix}` + ); + return { + zipFile: fs.existsSync(localZipPath) + ? readAsFile(localZipPath) + : fetchWordPress(wpDetails.url, monitor), + localZipPath, + }; + } catch (e) { + throw new Error( + `Could not resolve WordPress ${resolvedFilename} from local cache (you're offline)`, + { + cause: e, + } + ); + } +} + export async function resolveWPRelease(version = 'latest') { // Support custom URLs if (version.startsWith('https://') || version.startsWith('http://')) {