Skip to content

[Playground CLI] explore why plugin files don't exist after mounting #2347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 43 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6e093a7
Mount tests
bgrgicak Jul 8, 2025
1e38f50
Create directory node before mounting
bgrgicak Jul 8, 2025
6619235
When mounting a file create a empty file node instead of a directory …
bgrgicak Jul 9, 2025
8ac28d2
Remove the restriction which allows only directory mounting during co…
bgrgicak Jul 9, 2025
6a42ec1
Recompile PHP 8.0 Asyncify used by the mount and symlink test
bgrgicak Jul 9, 2025
deb9f85
Create mount point only if lookup throws error ENOENT
bgrgicak Jul 9, 2025
d18f5fa
Remove node created by mount after unmount
bgrgicak Jul 9, 2025
652563a
Test symlink mounting
bgrgicak Jul 9, 2025
92d0ce7
Force follow to always be true in FS.lookupPath
bgrgicak Jul 10, 2025
9976df4
Set follow to true by default, but allow overriding
bgrgicak Jul 14, 2025
b428d85
Fix symlink mounting and copying
bgrgicak Jul 14, 2025
2ae32b1
File operations
bgrgicak Jul 15, 2025
d52b3b4
Directory operations
bgrgicak Jul 15, 2025
868316e
Add symlinked directory and file tests
bgrgicak Jul 15, 2025
8f637e9
Merge branch 'trunk' into add/file-mounting-to-nodefs
bgrgicak Jul 15, 2025
9517bc5
Revert mountNODEFSMountPoint
bgrgicak Jul 15, 2025
d3ab7b7
Remove debug logs
bgrgicak Jul 15, 2025
cbdc543
Replace mount directory condition only once
bgrgicak Jul 15, 2025
ffbac8a
Fix linter issues
bgrgicak Jul 15, 2025
8c95634
Revert unrelated lint changes
bgrgicak Jul 15, 2025
bd97546
Remove TODO
bgrgicak Jul 15, 2025
1c180c5
Rename mounting to mount
bgrgicak Jul 15, 2025
4f6fda4
Don't create directories manually before mounting to NODEFS
bgrgicak Jul 15, 2025
84e2e07
Merge branch 'trunk' into add/file-mounting-to-nodefs
bgrgicak Jul 15, 2025
9dd8ea4
Recompile PHP-wasm Node
bgrgicak Jul 15, 2025
4bc154c
Merge branch 'add/file-mounting-to-nodefs' into fix/lookup-path-not-f…
bgrgicak Jul 15, 2025
7fa179c
Update packages/php-wasm/compile/php/Dockerfile
bgrgicak Jul 16, 2025
952c6d6
Address feedback
bgrgicak Jul 16, 2025
648696c
Fix linter errors
bgrgicak Jul 16, 2025
906359d
Merge branch 'add/file-mounting-to-nodefs' into fix/lookup-path-not-f…
bgrgicak Jul 16, 2025
bdf5495
Prevent FSHelper.rmdir from following symlinks when checking for a mo…
bgrgicak Jul 16, 2025
1fd538b
Create parent directory before creating the mount node
bgrgicak Jul 16, 2025
a267805
Merge branch 'add/file-mounting-to-nodefs' into fix/lookup-path-not-f…
bgrgicak Jul 16, 2025
4521055
Don't follow symlinks when checking for a mountpoint in rmdir
bgrgicak Jul 16, 2025
f675044
Merge branch 'add/file-mounting-to-nodefs' into fix/lookup-path-not-f…
bgrgicak Jul 16, 2025
b249834
Add test script
bgrgicak Jul 16, 2025
a7d39e0
Add test script
bgrgicak Jul 16, 2025
706c100
Merge branch 'fix/lookup-path-not-following-symlink-mounts' of github…
bgrgicak Jul 16, 2025
ae7033b
Narrow down the follow: false argument to php functions that call FS.…
bgrgicak Jul 17, 2025
0defd5e
Merge branch 'trunk' into fix/lookup-path-not-following-symlink-mounts
bgrgicak Jul 18, 2025
26a6795
Make plugin-symlink relative to repo
brandonpayton Jul 19, 2025
d003c4f
Fix typo: /internals/ to /internal/
brandonpayton Jul 22, 2025
28f3d76
Add /internal/symlinks to ProxyFS paths
brandonpayton Jul 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions blueprint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"preferredVersions": {
"php": "8.0",
"wp": "6.7"
},
"steps": [
{
"step": "defineWpConfigConsts",
"consts": {
"DISABLE_WP_CRON": false
}
},
{
"step": "activatePlugin",
"pluginPath": "/wordpress/wp-content/plugins/plugin"
}
]
}
651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_7_2.js

Large diffs are not rendered by default.

651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_7_3.js

Large diffs are not rendered by default.

651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_7_4.js

Large diffs are not rendered by default.

651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_8_0.js

Large diffs are not rendered by default.

651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_8_1.js

Large diffs are not rendered by default.

651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_8_2.js

Large diffs are not rendered by default.

651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_8_3.js

Large diffs are not rendered by default.

651 changes: 184 additions & 467 deletions packages/php-wasm/node/asyncify/php_8_4.js

Large diffs are not rendered by default.

44 changes: 42 additions & 2 deletions packages/php-wasm/node/src/lib/load-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,46 @@ export async function loadNodeRuntime(
* in the Emscripten's filesystem and mount the OS directory
* to the Emscripten filesystem.
*
* The directory is mounted to the `/internals/symlinks` directory to avoid
* The directory is mounted to the `/internal/symlinks` directory to avoid
* conflicts with existing VFS directories.
* We can set a arbitrary mount path because readlink is the source of truth
* for the path and Emscripten will accept it as if it was the real link path.
*/
if (options?.followSymlinks === true) {
const fsStat = phpRuntime.FS.stat;
phpRuntime.FS.stat = (path: string, dontFollow: boolean) => {
if (dontFollow === true && path.includes('woocommerce')) {
const obj: any = {};
if ('captureStackTrace' in Error) {
Error.captureStackTrace(obj);
}
const stack = obj.stack.split('\n');
const lastStackLine = stack[stack.length - 1];
const functionName = lastStackLine.trim().split(' ')[1];

/**
* One of these functions is called with dontFollow set to true
* and causes plugin activation to fail with a "Plugin file does not exist" error.
*
* Potentially related to https://core.trac.wordpress.org/ticket/16953
*/
if (
[
'php.wasm.php_stat',
'php.wasm.__fstatat',
'php.wasm.tsrm_realpath_r',
].includes(functionName)
) {
console.log(
`[DEBUG] dontFollow override for function ${functionName} for path ${path}`,
obj.stack
);
dontFollow = false;
}
}
return fsStat(path, dontFollow);
};

phpRuntime.FS.filesystems.NODEFS.node_ops.readlink = (
node: any
) => {
Expand All @@ -106,7 +140,7 @@ export async function loadNodeRuntime(
)
);
const symlinkPath = joinPaths(
`/internals/symlinks`,
`/internal/symlinks`,
absoluteSourcePath
);
if (
Expand All @@ -129,6 +163,12 @@ export async function loadNodeRuntime(
{ root: absoluteSourcePath },
symlinkPath
);
console.log(
'\n[DEBUG] readlink mounted symlinked path',
absoluteSourcePath,
'->',
symlinkPath
);
}
return symlinkPath;
};
Expand Down
15 changes: 15 additions & 0 deletions packages/php-wasm/node/src/lib/node-fs-mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ export function createNodeFsMountHandler(localPath: string): MountHandler {
throw e;
}
FS.mount(FS.filesystems['NODEFS'], { root: localPath }, vfsMountPoint);
console.log(
'[DEBUG] createNodeFsMountHandler mounted local path',
localPath,
'to',
vfsMountPoint
);

php.run({
code: `<?php echo json_encode(file_exists('${vfsMountPoint}'));`,
}).then((result) => {
console.log(
'[DEBUG] createNodeFsMountHandler mounted plugin path exists',
result.json
);
});
return () => {
FS!.unmount(vfsMountPoint);
if (removeVfsNode) {
Expand Down
11 changes: 11 additions & 0 deletions packages/playground/cli/src/run-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,17 @@ export async function runCLI(args: RunCLIArgs): Promise<RunCLIServer> {
wordPressReady = true;
logger.log(`Booted!`);

playground
.run({
code: `<?php echo json_encode(file_exists('/wordpress/wp-content/plugins/plugin'));`,
})
.then((result) => {
console.log(
'\n[DEBUG] runCLI mounted plugin path exists',
result.json
);
});

if (compiledBlueprint) {
logger.log(`Running the Blueprint...`);
await runBlueprintSteps(compiledBlueprint, playground);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export function getSqliteDriverModuleDetails(
url: string;
} {
switch (version) {

case 'develop':
/** @ts-ignore */
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"develop": "develop",
"v2.1.16": "v2.1.16"
}
"develop": "develop",
"v2.1.16": "v2.1.16"
}
1 change: 1 addition & 0 deletions packages/playground/wordpress/src/boot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export async function bootRequestHandler(options: BootRequestHandlerOptions) {
'/tmp',
requestHandler.documentRoot,
'/internal/shared',
'/internal/symlinks',
]);
}

Expand Down
1 change: 1 addition & 0 deletions plugin-symlink
21 changes: 21 additions & 0 deletions run-cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

current_dir=$(pwd)
plugin_dir=$current_dir/packages/playground/cli/src/test/mount-examples/plugin
symlink_dir=$current_dir/plugin-symlink

# symlink plugin
ln -s $plugin_dir $symlink_dir

# run cli
node \
--experimental-wasm-jspi \
--experimental-strip-types \
--experimental-transform-types \
--import ./packages/meta/src/node-es-module-loader/register.mts \
./packages/playground/cli/src/cli.ts \
server \
--port=9400 \
--follow-symlinks \
--blueprint=$current_dir/blueprint.json \
--mount=$symlink_dir:/wordpress/wp-content/plugins/plugin