Skip to content

Commit 5eb3f16

Browse files
committed
Refactor php-wasm-cli to maintain consistency across the different clis
1 parent 47d921f commit 5eb3f16

File tree

12 files changed

+114
-50
lines changed

12 files changed

+114
-50
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ php.js.bak
6464
# @php-wasm/cli saves this file to disk so PHP has access to it.
6565
# Since it is dynamically generated from the Node.js TLS module,
6666
# we do not want to commit it to the repository.
67-
packages/php-wasm/cli/src/ca-bundle.crt
67+
packages/php-wasm/cli/src/lib/ca-bundle.crt
6868

6969
# PHPUnit
7070
.phpunit.result.cache

packages/php-wasm/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
},
2222
"license": "GPL-2.0-or-later",
2323
"type": "module",
24-
"main": "main.js",
24+
"main": "cli.js",
2525
"bin": {
2626
"php-wasm-cli": "php-wasm.js"
2727
},

packages/php-wasm/cli/project.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"executor": "@nx/vite:build",
3030
"outputs": ["{options.outputPath}"],
3131
"options": {
32-
"main": "dist/packages/php-wasm/cli/main.js",
32+
"main": "dist/packages/php-wasm/cli/cli.js",
3333
"outputPath": "dist/packages/php-wasm/cli"
3434
},
3535
"defaultConfiguration": "production",
@@ -45,7 +45,7 @@
4545
"dev": {
4646
"executor": "nx:run-commands",
4747
"options": {
48-
"command": "node --no-warnings --experimental-wasm-stack-switching --experimental-wasm-jspi --loader=./packages/meta/src/node-es-module-loader/loader.mts ./packages/php-wasm/cli/src/main.ts",
48+
"command": "node --no-warnings --experimental-wasm-stack-switching --experimental-wasm-jspi --loader=./packages/meta/src/node-es-module-loader/loader.mts ./packages/php-wasm/cli/src/cli.ts",
4949
"tty": true
5050
}
5151
},
@@ -57,7 +57,7 @@
5757
"command": "node -e \"if (parseInt(process.versions.node) < 22) { console.error('Node.js version 22 or greater is required'); process.exit(1); }\"",
5858
"forwardAllArgs": false
5959
},
60-
"node --stack-trace-limit=100 --inspect --experimental-strip-types --experimental-transform-types --import ./packages/meta/src/node-es-module-loader/register.mts --watch ./packages/php-wasm/cli/src/main.ts"
60+
"node --stack-trace-limit=100 --inspect --experimental-strip-types --experimental-transform-types --import ./packages/meta/src/node-es-module-loader/register.mts --watch ./packages/php-wasm/cli/src/cli.ts"
6161
],
6262
"tty": true,
6363
"parallel": false
@@ -71,7 +71,7 @@
7171
"command": "node -e \"if (parseInt(process.versions.node) < 22) { console.error('Node.js version 22 or greater is required'); process.exit(1); }\"",
7272
"forwardAllArgs": false
7373
},
74-
"node --inspect --experimental-strip-types --experimental-transform-types --import ./packages/meta/src/node-es-module-loader/register.mts ./packages/php-wasm/cli/src/main.ts"
74+
"node --inspect --experimental-strip-types --experimental-transform-types --import ./packages/meta/src/node-es-module-loader/register.mts ./packages/php-wasm/cli/src/cli.ts"
7575
],
7676
"tty": true,
7777
"parallel": false
@@ -80,7 +80,7 @@
8080
"start": {
8181
"executor": "@wp-playground/nx-extensions:built-script",
8282
"options": {
83-
"scriptPath": "dist/packages/php-wasm/cli/main.js"
83+
"scriptPath": "dist/packages/php-wasm/cli/php-wasm.js"
8484
},
8585
"dependsOn": ["build"]
8686
},
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/usr/bin/env node
2-
import './main.js';
2+
import './run-cli.js';

packages/php-wasm/cli/src/cli.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { parseOptionsAndRunCLI } from './lib/run-cli';
2+
3+
parseOptionsAndRunCLI();

packages/php-wasm/cli/src/main.ts renamed to packages/php-wasm/cli/src/lib/run-cli.ts

Lines changed: 89 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,117 @@
1-
/**
2-
* A CLI script that runs PHP CLI via the WebAssembly build.
3-
*/
1+
import yargs from 'yargs';
2+
import { hideBin } from 'yargs/helpers';
43
import os from 'os';
54
import { writeFileSync, existsSync, mkdtempSync, chmodSync } from 'fs';
65
import { rootCertificates } from 'tls';
7-
86
import {
97
LatestSupportedPHPVersion,
108
SupportedPHPVersionsList,
119
} from '@php-wasm/universal';
1210
import type { SupportedPHPVersion } from '@php-wasm/universal';
13-
1411
import { FileLockManagerForNode } from '@php-wasm/node';
1512
import { PHP } from '@php-wasm/universal';
1613
import { loadNodeRuntime, useHostFilesystem } from '@php-wasm/node';
1714
import { startBridge } from '@php-wasm/xdebug-bridge';
1815
import path from 'path';
1916

20-
let args = process.argv.slice(2);
21-
if (!args.length) {
22-
args = ['--help'];
17+
interface CLIDefaults {
18+
directive: string[];
19+
config: string;
2320
}
2421

25-
const baseUrl = (import.meta || {}).url;
22+
interface CLIArgs {
23+
_: string[];
24+
config: string;
25+
directive: string[];
26+
xdebug?: boolean;
27+
experimentalDevtools?: boolean;
28+
}
2629

27-
// Write the ca-bundle.crt file to disk so that PHP can find it.
28-
const caBundlePath = new URL('ca-bundle.crt', baseUrl).pathname;
29-
if (!existsSync(caBundlePath)) {
30-
writeFileSync(caBundlePath, rootCertificates.join('\n'));
30+
function parseCliArgs(defaults: CLIDefaults) {
31+
return yargs(hideBin(process.argv))
32+
.usage(
33+
`
34+
PHP.wasm CLI
35+
36+
Usage: php-wasm-cli <command> [options]
37+
`
38+
)
39+
.option('config', {
40+
alias: 'c',
41+
type: 'string',
42+
describe: 'Path to configuration file',
43+
default: defaults.config,
44+
})
45+
.option('directive', {
46+
alias: 'd',
47+
type: 'array',
48+
describe: 'Set configuration directives (key=value)',
49+
default: defaults.directive,
50+
})
51+
.option('xdebug', {
52+
type: 'boolean',
53+
describe: 'Enable Xdebug.',
54+
default: false,
55+
})
56+
.option('experimental-devtools', {
57+
type: 'boolean',
58+
describe: 'Enable experimental browser development tools.',
59+
default: false,
60+
})
61+
.strictCommands()
62+
.help()
63+
.epilog(
64+
`
65+
Examples:
66+
php-wasm-cli # Start with default settings
67+
php-wasm-cli --config /path/to/php.ini # Run PHP CLI with custom config file
68+
php-wasm-cli --xdebug --experimental-devtools # Enable Xdebug and Devtools
69+
`
70+
)
71+
.parseSync() as CLIArgs;
3172
}
32-
args.unshift('-d', `openssl.cafile=${caBundlePath}`);
3373

34-
async function run() {
35-
const defaultPhpIniPath = new URL('php.ini', baseUrl).pathname;
74+
function mapArgsArray(args: CLIArgs): string[] {
75+
const argv: string[] = [];
76+
77+
if (args.config) {
78+
argv.push('-c', args.config);
79+
}
80+
81+
if (Array.isArray(args.directive)) {
82+
args.directive.forEach((d) => {
83+
argv.push('-d', d);
84+
});
85+
}
86+
87+
if (Array.isArray(args._)) {
88+
argv.push(...args._);
89+
}
90+
91+
return argv;
92+
}
93+
94+
export async function parseOptionsAndRunCLI(): Promise<void> {
3695
const phpVersion = (process.env['PHP'] ||
3796
LatestSupportedPHPVersion) as SupportedPHPVersion;
3897
if (!SupportedPHPVersionsList.includes(phpVersion)) {
3998
throw new Error(`Unsupported PHP version ${phpVersion}`);
4099
}
41100

42-
const hasXdebugOption = args.some((arg) => arg.startsWith('--xdebug'));
43-
if (hasXdebugOption) {
44-
args = args.filter((arg) => arg !== '--xdebug');
45-
}
101+
const baseUrl = (import.meta || {}).url;
46102

47-
const hasDevtoolsOption = args.some((arg) =>
48-
arg.startsWith('--experimental-devtools')
49-
);
50-
if (hasDevtoolsOption) {
51-
args = args.filter((arg) => arg !== '--experimental-devtools');
103+
const defaultPhpIniPath = new URL('php.ini', baseUrl).pathname;
104+
// Write the ca-bundle.crt file to disk so that PHP can find it.
105+
const caBundlePath = new URL('ca-bundle.crt', baseUrl).pathname;
106+
if (!existsSync(caBundlePath)) {
107+
writeFileSync(caBundlePath, rootCertificates.join('\n'));
52108
}
53109

110+
const args = parseCliArgs({
111+
directive: [`openssl.cafile=${caBundlePath}`],
112+
config: defaultPhpIniPath,
113+
});
114+
54115
// npm scripts set the TMPDIR env variable
55116
// PHP accepts a TMPDIR env variable and expects it to
56117
// be a writable directory within the PHP filesystem.
@@ -99,24 +160,20 @@ ${process.argv[0]} ${process.execArgv.join(' ')} ${process.argv[1]}
99160
PATH: `${tempDir}:${envVariables['PATH']}`,
100161
},
101162
},
102-
withXdebug: hasXdebugOption,
163+
withXdebug: args.xdebug,
103164
})
104165
);
105166

106167
useHostFilesystem(php);
107168

108-
if (hasDevtoolsOption && hasXdebugOption) {
169+
if (args.experimentalDevtools && args.xdebug) {
109170
const bridge = await startBridge({ breakOnFirstLine: true });
110171

111172
bridge.start();
112173
}
113174

114-
const hasMinusCOption = args.some((arg) => arg.startsWith('-c'));
115-
if (!hasMinusCOption) {
116-
args.unshift('-c', defaultPhpIniPath);
117-
}
175+
const response = await php.cli(['php', ...mapArgsArray(args)]);
118176

119-
const response = await php.cli(['php', ...args]);
120177
response.stderr.pipeTo(
121178
new WritableStream({
122179
write(chunk) {
@@ -147,5 +204,3 @@ ${process.argv[0]} ${process.execArgv.join(' ')} ${process.argv[1]}
147204
}, 100);
148205
});
149206
}
150-
151-
run();

packages/php-wasm/cli/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default defineConfig({
3535
'ws',
3636
'os',
3737
],
38-
input: 'packages/php-wasm/cli/src/main.ts',
38+
input: 'packages/php-wasm/cli/src/cli.ts',
3939
output: {
4040
format: 'esm',
4141
entryFileNames: '[name].js',
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { main } from './lib/run-cli';
1+
import { parseOptionsAndRunCLI } from './lib/run-cli';
22

3-
main();
3+
parseOptionsAndRunCLI();

packages/php-wasm/xdebug-bridge/src/lib/run-cli.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ Usage: xdebug-bridge [options]
3131
.option('port', {
3232
alias: 'p',
3333
type: 'number',
34-
description: 'Xdebug port to listen on',
34+
describe: 'Xdebug port to listen on',
3535
default: 9003,
3636
})
3737
.option('host', {
3838
alias: 'h',
3939
type: 'string',
40-
description: 'Xdebug host to bind to',
40+
describe: 'Xdebug host to bind to',
4141
default: 'localhost',
4242
})
4343
.option('php-root', {
@@ -65,7 +65,7 @@ Examples:
6565
.parseSync() as CLIArgs;
6666
}
6767

68-
export async function main(): Promise<void> {
68+
export async function parseOptionsAndRunCLI(): Promise<void> {
6969
const args = parseCliArgs();
7070

7171
if (args.help) {

0 commit comments

Comments
 (0)