Skip to content
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

add php extension validation #104

Merged
merged 1 commit into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions build-packages/magento-scripts/lib/tasks/php/bundled-extensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const bundledExtensions = [
'bz2',
'bcmath',
'ctype',
'curl',
'intl',
'dom',
'filter',
'hash',
'sockets',
'iconv',
'json',
'mbstring',
'openssl',
'xml',
'mysql',
'pdo',
'soap',
'xmlrpc',
'xml',
'zip',
'fpm',
'gd'
];

module.exports = {
bundledExtensions
};
66 changes: 18 additions & 48 deletions build-packages/magento-scripts/lib/tasks/php/compile-options.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
const { bundledExtensions } = require('./bundled-extensions');

const darwinVariants = [
'openssl=$(brew --prefix [email protected])', // ="$(brew --prefix [email protected])"
'curl=$(brew --prefix curl)',
'intl=$(brew --prefix icu4c)',
'bz2="$(brew --prefix bzip2)"'
];

const compileOptions = {
linux: {
cpuCount: '$(nproc)',
variants: [
'+bz2',
'+bcmath',
'+ctype',
'+curl',
'+intl',
'+dom',
'+filter',
'+hash',
'+sockets',
'+iconv',
'+json',
'+mbstring',
'+openssl',
'+xml',
'+mysql',
'+pdo',
'+soap',
'+xmlrpc',
'+xml',
'+zip',
'+fpm',
'+gd'
],
variants: bundledExtensions.map((ext) => `+${ext}`),
extraOptions: [
'--with-freetype-dir=/usr/include/freetype2',
'--with-openssl=/usr/',
Expand All @@ -39,30 +25,14 @@ const compileOptions = {
},
darwin: {
cpuCount: '$(sysctl -n hw.ncpu)',
variants: [
'+neutral',
'+bz2="$(brew --prefix bzip2)"',
'+bcmath',
'+ctype',
'+curl=$(brew --prefix curl)',
'+intl=$(brew --prefix icu4c)',
'+dom',
'+filter',
'+hash',
'+iconv',
'+json',
'+mbstring',
'+openssl=$(brew --prefix [email protected])', // ="$(brew --prefix [email protected])"
'+xml',
'+mysql',
'+pdo',
'+soap',
'+xmlrpc',
'+xml',
'+zip',
'+fpm',
'+gd'
],
variants: bundledExtensions.map((ext) => {
const darwinVariant = darwinVariants.find((dv) => dv.startsWith(ext));
if (darwinVariant) {
return `+${darwinVariant}`;
}

return `+${ext}`;
}),
extraOptions: [
'--with-zlib-dir=$(brew --prefix zlib)',
'--with-iconv=$(brew --prefix libiconv)',
Expand Down
4 changes: 2 additions & 2 deletions build-packages/magento-scripts/lib/tasks/php/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const compileOptions = require('./compile-options');
/**
* @type {() => import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
*/
const compile = () => ({
const compilePHP = () => ({
title: 'Compiling PHP',
task: async ({ config: { php } }, task) => {
const platformCompileOptions = compileOptions[process.platform];
Expand Down Expand Up @@ -44,4 +44,4 @@ const compile = () => ({
}
});

module.exports = compile;
module.exports = compilePHP;
73 changes: 7 additions & 66 deletions build-packages/magento-scripts/lib/tasks/php/configure.js
Original file line number Diff line number Diff line change
@@ -1,76 +1,17 @@
/* eslint-disable max-len */
const path = require('path');
const fs = require('fs');
const { execAsyncSpawn } = require('../../util/exec-async-command');
const pathExists = require('../../util/path-exists');
const enableExtension = require('./extensions/enable');
const installExtension = require('./extensions/install');
const disableExtension = require('./extensions/disable');
const phpbrewConfig = require('../../config/phpbrew');

/**
* Get enabled extensions list with versions
* @param {import('../../../typings/context').ListrContext['config']} param0
* @returns {Promise<{[key: string]: string}}>}
*/
const getEnabledExtensions = async ({ php }) => {
const output = await execAsyncSpawn(
`${ php.binPath } -c ${php.iniPath} -r 'foreach (get_loaded_extensions() as $extension) echo "$extension:" . phpversion($extension) . "\n";'`
);

return output
.split('\n')
.map((m) => {
// eslint-disable-next-line no-unused-vars
const [_, moduleName, moduleVersion] = m.match(/(.+):(.+)/i);

return [moduleName, moduleVersion];
})
.reduce((acc, [name, version]) => ({ ...acc, [name]: version }), {});
};

/**
* Get disabled extensions list
* @param {import('../../../typings/context').ListrContext['config']} param0
* @returns {Promise<string[]>}
*/
const getDisabledExtensions = async ({ php }) => {
const extensionsIniDirectory = path.join(phpbrewConfig.phpPath, `php-${php.version}`, 'var', 'db');

if (!await pathExists(extensionsIniDirectory)) {
return [];
}

const extensionIniList = await fs.promises.readdir(
extensionsIniDirectory,
{
encoding: 'utf-8',
withFileTypes: true
}
);

return extensionIniList.filter((f) => f.isFile() && f.name.endsWith('.disabled')).map((f) => f.name.replace('.disabled', ''));
};

/**
* Get installed extensions
* @param {import('../../../typings/context').ListrContext['config']} param0
* @returns {Promise<string[]>}
*/
const getInstalledExtensions = async ({ php }) => {
const extensionDirectory = path.join(phpbrewConfig.buildPath, `php-${php.version}`, 'ext');

const availableExtensions = await fs.promises.readdir(extensionDirectory, {
encoding: 'utf-8'
});

return availableExtensions;
};
const {
getEnabledExtensions,
getInstalledExtensions,
getDisabledExtensions
} = require('./extensions');

/**
* @returns {import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
*/
const configure = () => ({
const configurePHP = () => ({
title: 'Configuring PHP extensions',
task: async ({ config, debug }, task) => {
const { php, php: { disabledExtensions = [] } } = config;
Expand Down Expand Up @@ -145,4 +86,4 @@ const configure = () => ({
}
});

module.exports = configure;
module.exports = configurePHP;
71 changes: 71 additions & 0 deletions build-packages/magento-scripts/lib/tasks/php/extensions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* eslint-disable max-len */
const path = require('path');
const fs = require('fs');
const { execAsyncSpawn } = require('../../../util/exec-async-command');
const pathExists = require('../../../util/path-exists');
const phpbrewConfig = require('../../../config/phpbrew');

/**
* Get enabled extensions list with versions
* @param {import('../../../../typings/context').ListrContext['config']} param0
* @returns {Promise<{[key: string]: string}}>}
*/
const getEnabledExtensions = async ({ php }) => {
const output = await execAsyncSpawn(
`${ php.binPath } -c ${php.iniPath} -r 'foreach (get_loaded_extensions() as $extension) echo "$extension:" . phpversion($extension) . "\n";'`
);

return output
.split('\n')
.map((m) => {
// eslint-disable-next-line no-unused-vars
const [_, moduleName, moduleVersion] = m.match(/(.+):(.+)/i);

return [moduleName, moduleVersion];
})
.reduce((acc, [name, version]) => ({ ...acc, [name]: version }), {});
};

/**
* Get disabled extensions list
* @param {import('../../../../typings/context').ListrContext['config']} param0
* @returns {Promise<string[]>}
*/
const getDisabledExtensions = async ({ php }) => {
const extensionsIniDirectory = path.join(phpbrewConfig.phpPath, `php-${php.version}`, 'var', 'db');

if (!await pathExists(extensionsIniDirectory)) {
return [];
}

const extensionIniList = await fs.promises.readdir(
extensionsIniDirectory,
{
encoding: 'utf-8',
withFileTypes: true
}
);

return extensionIniList.filter((f) => f.isFile() && f.name.endsWith('.disabled')).map((f) => f.name.replace('.disabled', ''));
};

/**
* Get installed extensions
* @param {import('../../../../typings/context').ListrContext['config']} param0
* @returns {Promise<string[]>}
*/
const getInstalledExtensions = async ({ php }) => {
const extensionDirectory = path.join(phpbrewConfig.buildPath, `php-${php.version}`, 'ext');

const availableExtensions = await fs.promises.readdir(extensionDirectory, {
encoding: 'utf-8'
});

return availableExtensions;
};

module.exports = {
getEnabledExtensions,
getDisabledExtensions,
getInstalledExtensions
};
10 changes: 5 additions & 5 deletions build-packages/magento-scripts/lib/tasks/php/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const fs = require('fs');
const path = require('path');
const logger = require('@scandipwa/scandipwa-dev-utils/logger');
const pathExists = require('../../util/path-exists');
const compile = require('./compile');
const configure = require('./configure');
const compilePhp = require('./compile');
const configurePhp = require('./configure');
const updatePhpBrew = require('./update-phpbrew');
const phpbrewConfig = require('../../config/phpbrew');

Expand Down Expand Up @@ -63,7 +63,7 @@ const installPhp = () => ({
// eslint-disable-next-line consistent-return
return task.newListr([
updatePhpBrew(),
compile()
compilePhp()
], {
concurrent: false,
exitOnError: true
Expand All @@ -73,6 +73,6 @@ const installPhp = () => ({

module.exports = {
installPhp,
compilePhp: compile,
configurePhp: configure
compilePhp,
configurePhp
};
67 changes: 67 additions & 0 deletions build-packages/magento-scripts/lib/tasks/php/validate-php.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const logger = require('@scandipwa/scandipwa-dev-utils/logger');
const { bundledExtensions } = require('./bundled-extensions');
const configurePHP = require('./configure');
const { getEnabledExtensions } = require('./extensions');
const { installPhp } = require('./index');

/**
* @type {() => import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
*/
const validatePHPInstallation = () => ({
title: 'Validating PHP installation',
task: async (ctx, task) => {
const enabledExtensions = await getEnabledExtensions(ctx.config);
const enabledExtensionsKeys = Object.keys(enabledExtensions);

enabledExtensionsKeys.push('fpm');

if (enabledExtensionsKeys.some((ext) => ext.includes('mysql'))) {
enabledExtensionsKeys.push('mysql');
}

const missingBundledExtensions = bundledExtensions.filter(
(ext) => !enabledExtensionsKeys.some(
(ex) => ex.toLowerCase() === ext.toLowerCase()
)
);

if (missingBundledExtensions.length > 0) {
const selectedOption = await task.prompt({
type: 'Select',
message: `Your PHP version compiled by PHPBrew is missing important extensions that are bundled by default by ${logger.style.misc('magento-scripts')}
Maybe you ran PHPBrew by yourself?

Please, consider recompiling PHP using ${logger.style.misc('magento-scripts')}.

${logger.style.command('npm start -- --recompile-php')}
`,
choices: [
{
name: 'recompile-php',
message: `I want ${logger.style.misc('magento-scripts')} to recompile PHP`
},
{
name: 'skip',
message: 'I am sure that it is okay and want to continue with this setup'
}
]
});

if (selectedOption === 'skip') {
task.skip('User skipped PHP recompilation');
return;
}

ctx.recompilePhp = true;

return task.newListr([
installPhp(),
configurePHP()
], {
concurrent: false
});
}
}
});

module.exports = validatePHPInstallation;
2 changes: 2 additions & 0 deletions build-packages/magento-scripts/lib/tasks/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const enableMagentoComposerPlugins = require('./magento/enable-magento-composer-
const getIsWsl = require('../util/is-wsl');
const checkForXDGOpen = require('../util/xdg-open-exists');
const { getInstanceMetadata, constants: { WEB_LOCATION_TITLE } } = require('../util/instance-metadata');
const validatePHPInstallation = require('./php/validate-php');

/**
* @type {() => import('listr2').ListrTask<import('../../typings/context').ListrContext>}
Expand Down Expand Up @@ -113,6 +114,7 @@ const configureProject = () => ({
})
},
configurePhp(),
validatePHPInstallation(),
installPrestissimo(),
installMagento(),
enableMagentoComposerPlugins(),
Expand Down