diff --git a/packages/wp-now/src/execute-php-file.ts b/packages/wp-now/src/execute-php-file.ts deleted file mode 100644 index 130569bf..00000000 --- a/packages/wp-now/src/execute-php-file.ts +++ /dev/null @@ -1,44 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import startWPNow from './wp-now'; -import { WPNowOptions } from './config'; -import { disableOutput } from './output'; - -/** - * - * Execute a PHP file given its path. For non index mode it loads WordPress context. - * - * @param {string} filePath - The path to the PHP file to be executed. - * @param {WPNowOptions} [options={}] - Optional configuration object for WPNow. Defaults to an empty object. - * @returns {Promise<{ name: string; status: 0; }>} - Returns a Promise that resolves to an object containing - * the exit name and status (0 for success). - * @throws {Error} - Throws an error if the specified file is not found or if an error occurs while executing the file. - */ -export async function executePHPFile( - filePath: string, - options: WPNowOptions = {} -) { - disableOutput(); - const { phpInstances } = await startWPNow({ - ...options, - numberOfPhpInstances: 2, - }); - const [, php] = phpInstances; - - // check if filePath exists - const absoluteFilePath = path.resolve(filePath); - if (!fs.existsSync(absoluteFilePath)) { - throw new Error(`Could not open input file: ${absoluteFilePath}`); - } - - try { - php.useHostFilesystem(); - await php.cli(['php', absoluteFilePath]); - } catch (resultOrError) { - const success = - resultOrError.name === 'ExitStatus' && resultOrError.status === 0; - if (!success) { - throw resultOrError; - } - } -} diff --git a/packages/wp-now/src/execute-php.ts b/packages/wp-now/src/execute-php.ts new file mode 100644 index 00000000..98c5adf7 --- /dev/null +++ b/packages/wp-now/src/execute-php.ts @@ -0,0 +1,40 @@ +import startWPNow from './wp-now'; +import { WPNowOptions } from './config'; +import { disableOutput } from './output'; + +/** + * Execute a PHP cli given its parameters. + * + * @param phpArgs - Arguments to pass to the PHP cli. The first argument should be the string 'php'. + * @param options - Optional configuration object for WPNow. Defaults to an empty object. + * @returns - Returns a Promise that resolves to an object containing + * the exit name and status (0 for success). + * @throws - Throws an error if the first element in phpArgs is not the string 'php'. + */ +export async function executePHP( + phpArgs: string[], + options: WPNowOptions = {} +) { + if (phpArgs[0] !== 'php') { + throw new Error( + 'The first argument to executePHP must be the string "php".' + ); + } + disableOutput(); + const { phpInstances } = await startWPNow({ + ...options, + numberOfPhpInstances: 2, + }); + const [, php] = phpInstances; + + try { + php.useHostFilesystem(); + await php.cli(phpArgs); + } catch (resultOrError) { + const success = + resultOrError.name === 'ExitStatus' && resultOrError.status === 0; + if (!success) { + throw resultOrError; + } + } +} diff --git a/packages/wp-now/src/run-cli.ts b/packages/wp-now/src/run-cli.ts index 382b6c8e..dcfb6b45 100644 --- a/packages/wp-now/src/run-cli.ts +++ b/packages/wp-now/src/run-cli.ts @@ -3,9 +3,9 @@ import { hideBin } from 'yargs/helpers'; import { startServer } from './start-server'; import { portFinder } from './port-finder'; import { SupportedPHPVersion } from '@php-wasm/universal'; -import getWpNowConfig from './config'; +import getWpNowConfig, { CliOptions } from './config'; import { spawn, SpawnOptionsWithoutStdio } from 'child_process'; -import { executePHPFile } from './execute-php-file'; +import { executePHP } from './execute-php'; import { output } from './output'; function startSpinner(message: string) { @@ -38,13 +38,16 @@ export async function runCli() { .scriptName('wp-now') .usage('$0 [args]') .check(async (argv) => { + const config: CliOptions = { + php: argv.php as SupportedPHPVersion, + path: argv.path as string, + }; + if (argv._[0] !== 'php') { + config.wp = argv.wp as string; + config.port = argv.port as number; + } try { - await getWpNowConfig({ - path: argv.path as string, - php: argv.php as SupportedPHPVersion, - wp: argv.wp as string, - port: argv.port as number, - }); + await getWpNowConfig(config); } catch (error) { return error.message; } @@ -87,22 +90,25 @@ export async function runCli() { } ) .command( - 'php ', - 'Run the php command passing the arguments for php cli', + 'php [..args]', + 'Run the php command passing the arguments to php cli', (yargs) => { commonParameters(yargs); - yargs.positional('file', { - describe: 'Path to the PHP file to run', - type: 'string', - }); + yargs.strict(false); }, async (argv) => { try { + // 0: node, 1: wp-now, 2: php, ...args + const args = process.argv.slice(2); const options = await getWpNowConfig({ path: argv.path as string, php: argv.php as SupportedPHPVersion, }); - await executePHPFile(argv.file as string, options); + const phpArgs = args.includes('--') + ? (argv._ as string[]) + : args; + // 0: php, ...args + await executePHP(phpArgs, options); process.exit(0); } catch (error) { console.error(error); diff --git a/packages/wp-now/src/tests/execute-php-file.spec.ts b/packages/wp-now/src/tests/execute-php-file.spec.ts deleted file mode 100644 index b539ebdb..00000000 --- a/packages/wp-now/src/tests/execute-php-file.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import fs from 'fs-extra'; -import path from 'path'; -import { executePHPFile } from '../execute-php-file'; -import getWpNowConfig from '../config'; - -const exampleDir = path.join(__dirname, 'execute-php-file'); - -test('php file execution in index mode', async () => { - const resultFilePath = path.join(exampleDir, 'hello-world-result.txt'); - // reset result file - fs.writeFileSync(resultFilePath, ''); - const options = await getWpNowConfig({ - path: exampleDir, - }); - await executePHPFile(path.join(exampleDir, 'hello-world.php'), options); - const output = fs.readFileSync(resultFilePath, 'utf8'); - expect(output).toBe('Hello World!'); -}); - -test('php file execution for each PHP Version', async () => { - const resultFilePath = path.join(exampleDir, 'php-version-result.txt'); - const options = await getWpNowConfig({ - path: exampleDir, - }); - await executePHPFile(path.join(exampleDir, 'php-version.php'), { - ...options, - phpVersion: '7.4', - }); - let output = fs.readFileSync(resultFilePath, 'utf8'); - expect(output.substring(0, 16)).toBe('PHP Version: 7.4'); - - await executePHPFile(path.join(exampleDir, 'php-version.php'), { - ...options, - phpVersion: '8.0', - }); - output = fs.readFileSync(resultFilePath, 'utf8'); - expect(output.substring(0, 16)).toBe('PHP Version: 8.0'); - - await executePHPFile(path.join(exampleDir, 'php-version.php'), { - ...options, - phpVersion: '8.2', - }); - output = fs.readFileSync(resultFilePath, 'utf8'); - expect(output.substring(0, 16)).toBe('PHP Version: 8.2'); - - fs.writeFileSync(resultFilePath, 'PHP Version: X.Y'); -}); diff --git a/packages/wp-now/src/tests/execute-php.spec.ts b/packages/wp-now/src/tests/execute-php.spec.ts new file mode 100644 index 00000000..f1ed1894 --- /dev/null +++ b/packages/wp-now/src/tests/execute-php.spec.ts @@ -0,0 +1,131 @@ +import fs from 'fs-extra'; +import path from 'path'; +import { executePHP } from '../execute-php'; +import getWpNowConfig from '../config'; +import { runCli } from '../run-cli'; + +const exampleDir = path.join(__dirname, 'execute-php'); + +test('php file execution in index mode', async () => { + const resultFilePath = path.join(exampleDir, 'hello-world-result.txt'); + // reset result file + fs.writeFileSync(resultFilePath, ''); + const options = await getWpNowConfig({ + path: exampleDir, + }); + await executePHP( + ['php', path.join(exampleDir, 'hello-world.php')], + options + ); + const output = fs.readFileSync(resultFilePath, 'utf8'); + expect(output).toBe('Hello World!'); +}); + +test('php file execution for each PHP Version', async () => { + const resultFilePath = path.join(exampleDir, 'php-version-result.txt'); + const options = await getWpNowConfig({ + path: exampleDir, + }); + await executePHP(['php', path.join(exampleDir, 'php-version.php')], { + ...options, + phpVersion: '7.4', + }); + let output = fs.readFileSync(resultFilePath, 'utf8'); + expect(output.substring(0, 16)).toBe('PHP Version: 7.4'); + + await executePHP(['php', path.join(exampleDir, 'php-version.php')], { + ...options, + phpVersion: '8.0', + }); + output = fs.readFileSync(resultFilePath, 'utf8'); + expect(output.substring(0, 16)).toBe('PHP Version: 8.0'); + + await executePHP(['php', path.join(exampleDir, 'php-version.php')], { + ...options, + phpVersion: '8.2', + }); + output = fs.readFileSync(resultFilePath, 'utf8'); + expect(output.substring(0, 16)).toBe('PHP Version: 8.2'); + + fs.writeFileSync(resultFilePath, 'PHP Version: X.Y'); +}); + +test('php throws an error if the first element is not the string "php"', async () => { + const options = await getWpNowConfig({ + path: exampleDir, + }); + try { + await executePHP( + ['word-different-to-php', path.join(exampleDir, 'php-version.php')], + { + ...options, + phpVersion: '7.4', + } + ); + } catch (error) { + expect(error.message).toBe( + 'The first argument to executePHP must be the string "php".' + ); + } +}); + +describe('validate php arguments passed through yargs', () => { + let output = ''; + let consoleLogMock; + let processExitMock; + const argv = process.argv; + beforeEach(() => { + consoleLogMock = vi + .spyOn(console, 'log') + .mockImplementation((newLine: string) => { + output += `${newLine}\n`; + }); + processExitMock = vi + .spyOn(process, 'exit') + .mockImplementation(() => null); + }); + + afterEach(() => { + output = ''; + process.argv = argv; + consoleLogMock.mockRestore(); + processExitMock.mockRestore(); + }); + + test('php should receive the correct yargs arguments', async () => { + process.argv = ['node', 'wp-now', 'php', '--', '--version']; + await runCli(); + expect(output).toMatch(/PHP 8\.0(.*)\(cli\)/i); + expect(processExitMock).toHaveBeenCalledWith(0); + }); + + test('wp-now should change the php version', async () => { + process.argv = [ + 'node', + 'wp-now', + 'php', + '--php=7.4', + '--', + '--version', + ]; + await runCli(); + expect(output).toMatch(/PHP 7\.4(.*)\(cli\)/i); + expect(processExitMock).toHaveBeenCalledWith(0); + }); + + test('php should execute a file', async () => { + const filePath = path.join(exampleDir, 'print-php-version.php'); + process.argv = ['node', 'wp-now', 'php', filePath]; + await runCli(); + expect(output).toMatch(/8\.0/i); + expect(processExitMock).toHaveBeenCalledWith(0); + }); + + test('php should execute a file and change php version', async () => { + const filePath = path.join(exampleDir, 'print-php-version.php'); + process.argv = ['node', 'wp-now', 'php', '--php=7.4', '--', filePath]; + await runCli(); + expect(output).toMatch(/7\.4/i); + expect(processExitMock).toHaveBeenCalledWith(0); + }); +}); diff --git a/packages/wp-now/src/tests/execute-php-file/hello-world-result.txt b/packages/wp-now/src/tests/execute-php/hello-world-result.txt similarity index 100% rename from packages/wp-now/src/tests/execute-php-file/hello-world-result.txt rename to packages/wp-now/src/tests/execute-php/hello-world-result.txt diff --git a/packages/wp-now/src/tests/execute-php-file/hello-world.php b/packages/wp-now/src/tests/execute-php/hello-world.php similarity index 100% rename from packages/wp-now/src/tests/execute-php-file/hello-world.php rename to packages/wp-now/src/tests/execute-php/hello-world.php diff --git a/packages/wp-now/src/tests/execute-php-file/index.php b/packages/wp-now/src/tests/execute-php/index.php similarity index 100% rename from packages/wp-now/src/tests/execute-php-file/index.php rename to packages/wp-now/src/tests/execute-php/index.php diff --git a/packages/wp-now/src/tests/execute-php-file/php-version-result.txt b/packages/wp-now/src/tests/execute-php/php-version-result.txt similarity index 100% rename from packages/wp-now/src/tests/execute-php-file/php-version-result.txt rename to packages/wp-now/src/tests/execute-php/php-version-result.txt diff --git a/packages/wp-now/src/tests/execute-php-file/php-version.php b/packages/wp-now/src/tests/execute-php/php-version.php similarity index 100% rename from packages/wp-now/src/tests/execute-php-file/php-version.php rename to packages/wp-now/src/tests/execute-php/php-version.php diff --git a/packages/wp-now/src/tests/execute-php/print-php-version.php b/packages/wp-now/src/tests/execute-php/print-php-version.php new file mode 100644 index 00000000..f80a041e --- /dev/null +++ b/packages/wp-now/src/tests/execute-php/print-php-version.php @@ -0,0 +1 @@ +