Skip to content

Commit 6e8cde5

Browse files
committed
PHP: Add listFiles options to IsomorphicLocalPHP and WebPHPEndpoint
The options argument for listFiles was added to BasePHP in #462. This commit adds it to an interface and a Web PHP Endpoint so that it can be used across the board in web and node.js applications
1 parent 47c2832 commit 6e8cde5

File tree

9 files changed

+86
-30
lines changed

9 files changed

+86
-30
lines changed

packages/php-wasm/universal/src/lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export type {
55
PHPOutput,
66
PHPRunOptions,
77
UniversalPHP,
8+
ListFilesOptions,
89
RmDirOptions,
910
HTTPMethod,
1011
PHPRequest,

packages/php-wasm/universal/src/lib/universal-php.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,10 @@ export interface IsomorphicLocalPHP extends RequestHandler {
222222
* Lists the files and directories in the given directory.
223223
*
224224
* @param path - The directory path to list.
225+
* @param options - Options for the listing.
225226
* @returns The list of files and directories in the given directory.
226227
*/
227-
listFiles(path: string): string[];
228+
listFiles(path: string, options?: ListFilesOptions): string[];
228229

229230
/**
230231
* Checks if a directory exists in the PHP filesystem.

packages/php-wasm/web/src/lib/web-php-endpoint.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
BasePHP,
33
IsomorphicLocalPHP,
4+
ListFilesOptions,
45
PHPRequest,
56
PHPResponse,
67
PHPRunOptions,
@@ -145,8 +146,8 @@ export class WebPHPEndpoint implements IsomorphicLocalPHP {
145146
}
146147

147148
/** @inheritDoc @php-wasm/web!WebPHP.listFiles */
148-
listFiles(path: string): string[] {
149-
return _private.get(this)!.php.listFiles(path);
149+
listFiles(path: string, options?: ListFilesOptions): string[] {
150+
return _private.get(this)!.php.listFiles(path, options);
150151
}
151152

152153
/** @inheritDoc @php-wasm/web!WebPHP.isDir */

packages/playground/blueprints/src/lib/resources.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export class VFSResource extends Resource {
164164

165165
/** @inheritDoc */
166166
get name() {
167-
return this.resource.path;
167+
return this.resource.path.split('/').pop() || '';
168168
}
169169
}
170170

packages/playground/blueprints/src/lib/steps/activate-plugin.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ foreach ( ( glob( $plugin_path . '/*.php' ) ?: array() ) as $file ) {
5151
echo 'NO_ENTRY_FILE';
5252
`,
5353
});
54-
if (result.errors) throw new Error(result.errors);
55-
if (result.text === 'NO_ENTRY_FILE') {
54+
if (result.text.endsWith('NO_ENTRY_FILE')) {
5655
throw new Error('Could not find plugin entry file.');
5756
}
5857
};

packages/playground/blueprints/src/lib/steps/install-asset.ts

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,17 @@ export async function installAsset(
3131
// Extract to temporary folder so we can find asset folder name
3232

3333
const zipFileName = zipFile.name;
34-
const tmpFolder = `/tmp/assets`;
34+
const assetNameGuess = zipFileName.replace(/\.zip$/, '');
35+
36+
const tmpUnzippedFilesPath = `/tmp/assets/${assetNameGuess}`;
3537
const tmpZipPath = `/tmp/${zipFileName}`;
3638

3739
const removeTmpFolder = () =>
38-
playground.rmdir(tmpFolder, {
40+
playground.rmdir(tmpUnzippedFilesPath, {
3941
recursive: true,
4042
});
4143

42-
if (await playground.fileExists(tmpFolder)) {
44+
if (await playground.fileExists(tmpUnzippedFilesPath)) {
4345
await removeTmpFolder();
4446
}
4547

@@ -54,35 +56,34 @@ export async function installAsset(
5456
try {
5557
await unzip(playground, {
5658
zipPath: tmpZipPath,
57-
extractToPath: tmpFolder,
59+
extractToPath: tmpUnzippedFilesPath,
5860
});
5961

60-
// Find extracted asset folder name
61-
62-
const files = await playground.listFiles(tmpFolder);
62+
// Find the path asset folder name
63+
const files = await playground.listFiles(tmpUnzippedFilesPath, {
64+
prependPath: true,
65+
});
6366

67+
/**
68+
* If the zip only contains a single entry that is directory,
69+
* we assume that's the asset folder. Otherwise, the zip
70+
* probably contains the plugin files without an intermediate folder.
71+
*/
72+
const zipHasRootFolder =
73+
files.length === 1 && (await playground.isDir(files[0]));
6474
let assetFolderName;
6575
let tmpAssetPath = '';
66-
67-
for (const file of files) {
68-
tmpAssetPath = `${tmpFolder}/${file}`;
69-
if (await playground.isDir(tmpAssetPath)) {
70-
assetFolderName = file;
71-
break;
72-
}
73-
}
74-
75-
if (!assetFolderName) {
76-
throw new Error(
77-
`The zip file should contain a single folder with files inside, but the provided zip file (${zipFileName}) does not contain such a folder.`
78-
);
76+
if (zipHasRootFolder) {
77+
tmpAssetPath = files[0];
78+
assetFolderName = files[0].split('/').pop()!;
79+
} else {
80+
tmpAssetPath = tmpUnzippedFilesPath;
81+
assetFolderName = assetNameGuess;
7982
}
8083

8184
// Move asset folder to target path
82-
8385
const assetFolderPath = `${targetPath}/${assetFolderName}`;
8486
await playground.mv(tmpAssetPath, assetFolderPath);
85-
8687
await cleanup();
8788

8889
return {

packages/playground/blueprints/src/lib/steps/install-plugin.spec.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ describe('Blueprint step installPlugin', () => {
1515

1616
it('should install a plugin', async () => {
1717
// Create test plugin
18-
1918
const pluginName = 'test-plugin';
2019

2120
php.mkdir(`/${pluginName}`);
@@ -28,7 +27,10 @@ describe('Blueprint step installPlugin', () => {
2827
const zipFileName = `${pluginName}-0.0.1.zip`;
2928

3029
await php.run({
31-
code: `<?php $zip = new ZipArchive(); $zip->open("${zipFileName}", ZIPARCHIVE::CREATE); $zip->addFile("/${pluginName}/index.php"); $zip->close();`,
30+
code: `<?php $zip = new ZipArchive();
31+
$zip->open("${zipFileName}", ZIPARCHIVE::CREATE);
32+
$zip->addFile("/${pluginName}/index.php");
33+
$zip->close();`,
3234
});
3335

3436
php.rmdir(`/${pluginName}`);
@@ -63,4 +65,50 @@ describe('Blueprint step installPlugin', () => {
6365

6466
expect(php.fileExists(`${pluginsPath}/${pluginName}`)).toBe(true);
6567
});
68+
69+
it('should install a plugin even when it is zipped directly without a root-level folder', async () => {
70+
// Create test plugin
71+
const pluginName = 'test-plugin';
72+
73+
php.writeFile('/index.php', `/**\n * Plugin Name: Test Plugin`);
74+
75+
// Note the package name is different from plugin folder name
76+
const zipFileName = `${pluginName}-0.0.1.zip`;
77+
78+
await php.run({
79+
code: `<?php $zip = new ZipArchive();
80+
$zip->open("${zipFileName}", ZIPARCHIVE::CREATE);
81+
$zip->addFile("/index.php");
82+
$zip->close();`,
83+
});
84+
85+
expect(php.fileExists(zipFileName)).toBe(true);
86+
87+
// Create plugins folder
88+
const rootPath = await php.documentRoot;
89+
const pluginsPath = `${rootPath}/wp-content/plugins`;
90+
91+
php.mkdir(pluginsPath);
92+
93+
await runBlueprintSteps(
94+
compileBlueprint({
95+
steps: [
96+
{
97+
step: 'installPlugin',
98+
pluginZipFile: {
99+
resource: 'vfs',
100+
path: zipFileName,
101+
},
102+
options: {
103+
activate: false,
104+
},
105+
},
106+
],
107+
}),
108+
php
109+
);
110+
111+
php.unlink(zipFileName);
112+
expect(php.fileExists(`${pluginsPath}/${pluginName}-0.0.1`)).toBe(true);
113+
});
66114
});

packages/playground/website/src/lib/make-blueprint.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ function applyGutenbergPRSteps(prNumber: number): StepDefinition[] {
5151
step: 'mkdir',
5252
path: '/wordpress/pr',
5353
},
54+
{
55+
step: 'mkdir',
56+
path: '/tmp',
57+
},
5458
{
5559
step: 'writeFile',
5660
path: '/wordpress/pr/pr.zip',

packages/playground/website/src/main.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ try {
3535
blueprint.preferredVersions!.wp =
3636
query.get('wp') || blueprint.preferredVersions!.wp || 'latest';
3737
}
38+
console.log(blueprint);
3839
} catch (e) {
3940
blueprint = makeBlueprint({
4041
php: query.get('php') || '8.0',

0 commit comments

Comments
 (0)