diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c1561c..af92fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ * Added logic to allow default `composer` version to be set based on PHP version. * Added `2.2` and `2.2-latest` shorthand options to install the latest stable 2.2 LTS version of `composer`. -* Set default `composer` version to `2.8.3` -* Set default `composer` version to `2.2.24` for PHP 5.3-7.2 -* Set default `composer` version to `1.10.27` for PHP <= 5.2 +* Set default `composer` version to `2-latest` +* Set default `composer` version to `2.2-latest` for PHP 5.3-7.2 +* Set default `composer` version to `1-latest` for PHP <= 5.2 +* Removed `composer` installation from images to prefer installing during app build * Fixed bug causing `composer` 2.2.x to be installed when `composer_version` was set to a single digit version such as `1` * Fixed mismatched `libsqlite3-dev` and `libsqlite3-0` versions in PHP 8.3 and 8.4 images diff --git a/builders/php.js b/builders/php.js index fc744f0..a40e797 100644 --- a/builders/php.js +++ b/builders/php.js @@ -6,32 +6,25 @@ const path = require('path'); const semver = require('semver'); const addBuildStep = require('./../utils/add-build-step'); -const composerVersions = { - '1': '1.10.27', - '2': '2.8.3', - '2.2': '2.2.24', -}; - /** * Get the appropriate Composer version based on the PHP version. - * @param {string} phpVersion - The PHP version. + * @param {semver} phpSemver - The PHP semantic version. * @return {string|boolean} - The Composer version or false if we cannot parse the version. */ -const getDefaultComposerVersion = phpVersion => { - phpVersion = semver.coerce(phpVersion); +const getDefaultComposerVersion = phpSemver => { // Don't set a default composer version if we cannot // parse the version such as with `custom`. - if (!phpVersion) return false; + if (!phpSemver) return false; - if (semver.lt(phpVersion, '5.3.2')) { + if (semver.lt(phpSemver, '5.3.2')) { // Use Composer 1 for PHP < 5.3.2 - return composerVersions['1']; - } else if (semver.lt(phpVersion, '7.3.0')) { + return '1'; + } else if (semver.lt(phpSemver, '7.3.0')) { // Use Composer 2.2 LTS for PHP < 7.3 - return composerVersions['2.2']; + return '2.2'; } else { // Use Composer 2 for PHP >= 7.3 - return composerVersions['2']; + return '2'; } }; @@ -60,13 +53,25 @@ const nginxConfig = options => ({ const xdebugConfig = host => ([ `client_host=${host}`, 'discover_client_host=1', - 'log=/tmp/xdebug.log', - 'remote_enable=true', + 'log=/tmp/xdebug.log', + 'remote_enable=true', `remote_host=${host}`, ].join(' ')); -/* - * Helper to build a package string +/** + * Helper function to build a package string by combining package name and version + * + * @param {string} pkg - The package name + * @param {string} version - The package version + * @return {string} The formatted package string, either "pkg:version" or just "pkg" if version is empty + * + * @example + * // Returns "php:7.4" + * pkger('php', '7.4'); + * + * @example + * // Returns "mysql" + * pkger('mysql', ''); */ const pkger = (pkg, version) => (!_.isEmpty(version)) ? `${pkg}:${version}` : pkg; @@ -172,11 +177,15 @@ module.exports = { // Merge the user config onto the default options options = parseConfig(_.merge({}, config, options)); + // Get the semver of the PHP version, NULL if we cannot parse it + const phpSemver = semver.coerce(options.version); + phpSemver && debug('Parsed PHP semantic version: %s', phpSemver); + // Mount our default php config options.volumes.push(`${options.confDest}/${options.defaultFiles._php}:${options.remoteFiles._php}`); options.volumes.push(`${options.confDest}/${options.defaultFiles.pool}:${options.remoteFiles.pool}`); // Shift on the docker entrypoint if this is a more recent version - if (options.version !== 'custom' && semver.gt(semver.coerce(options.version), '5.5.0')) { + if (phpSemver && semver.gt(phpSemver, '5.5.0')) { options.command.unshift('docker-php-entrypoint'); } @@ -202,28 +211,38 @@ module.exports = { }; options.info = {via: options.via}; - // Add our composer things to run step - if (!_.isEmpty(options.composer)) { - const commands = - require('../utils/get-install-commands')(options.composer, pkger, ['composer', 'global', 'require', '-n']); - addBuildStep(commands, options._app, options.name, 'build_internal'); + // Determine the appropriate composer version to install if not specified + if (options.composer_version === true || options.composer_version === '') { + options.composer_version = getDefaultComposerVersion(phpSemver); + } else if (typeof options.composer_version === 'number') { + options.composer_version = options.composer_version.toString(); + } + const usingComposer1 = options.composer_version && semver.satisfies(options.composer_version, '1.x'); + + // Add prestissimo as a global package for Composer 1.x performance improvements. Requires PHP >= 5.3 + if (usingComposer1 && phpSemver && semver.gte(phpSemver, '5.3.0')) { + options.composer = options.composer || {}; + options.composer = {'hirak/prestissimo': '*', ...options.composer}; } - // Add activate steps for xdebug + // Add build step to enable xdebug if (options.xdebug) { addBuildStep(['docker-php-ext-enable xdebug'], options._app, options.name, 'build_as_root_internal'); } - // Determine the appropriate composer version if not already set - if (options.composer_version === true || options.composer_version === '') { - options.composer_version = getDefaultComposerVersion(options.version); + // Add build step to install our Composer global packages + if (!_.isEmpty(options.composer)) { + const commands = + require('../utils/get-install-commands')(options.composer, pkger, ['composer', 'global', 'require', '-n']); + addBuildStep(commands, options._app, options.name, 'build_internal'); } - // Install the desired composer version + // Install the desired composer version as the first `build_internal` build step if (options.composer_version) { debug('Installing composer version %s', options.composer_version); const commands = [`/helpers/install-composer.sh ${options.composer_version}`]; - addBuildStep(commands, options._app, options.name, 'build_internal', true); + const firstStep = true; + addBuildStep(commands, options._app, options.name, 'build_internal', firstStep); } // Add in nginx if we need to diff --git a/docs/config.md b/docs/config.md index c6cc1a4..7c7e618 100644 --- a/docs/config.md +++ b/docs/config.md @@ -18,7 +18,7 @@ services: webroot: . xdebug: false composer: [] - composer_version: '2.2.12' + composer_version: '2' # Below only valid for via: cli command: tail -f /dev/null config: @@ -161,16 +161,22 @@ You can use `lando info --deep | grep IPAddress` to help discover the correct ho ## Installing composer -As of Lando `3.0.17` you can configure the version of `composer` you would like to install. This _should_ respect any of the versions listed on the [Composer download page](https://getcomposer.org/download/) but it is required you specify down to the patch version. +Lando automatically installs the latest compatible version of Composer based on your specified PHP version: + +- PHP >= 7.3: Composer 2.x +- PHP >= 5.3.2 and < 7.3: Composer 2.2 LTS +- PHP < 5.3.2: Composer 1.x + +You can customize the Composer version by specifying either a specific version number or using a channel alias: ```yaml services: myservice: - type: php - composer_version: "1.10.1" + type: php:8.2 + composer_version: "2.6.5" # Install specific version ``` -You can also choose to ignore the `composer` install step by setting `composer_version: false`. This will use whatever version of `composer` was last bundled with our `php` image. The following "convenience flags" are also available: +The following channel aliases are available: ```yaml # Install the latest stable 1.x version @@ -192,6 +198,8 @@ composer_version: preview composer_version: snapshot ``` +You can disable Composer installation entirely by setting `composer_version: false`. + ## Installing global dependencies You can also use the `composer` key if you need to require any [global composer dependenices](https://getcomposer.org/doc/03-cli.md#require). This follows the same syntax as your normal [`composer.json`](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup) except written as YAML instead of JSON. diff --git a/images/5.6-apache/Dockerfile b/images/5.6-apache/Dockerfile index 3ca28dc..9a6516a 100644 --- a/images/5.6-apache/Dockerfile +++ b/images/5.6-apache/Dockerfile @@ -72,11 +72,7 @@ RUN \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/5.6-fpm/Dockerfile b/images/5.6-fpm/Dockerfile index ff72e07..412c0fa 100644 --- a/images/5.6-fpm/Dockerfile +++ b/images/5.6-fpm/Dockerfile @@ -72,12 +72,7 @@ RUN \ intl \ gettext \ pcntl \ - # Install composer - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/7.0-apache/Dockerfile b/images/7.0-apache/Dockerfile index e1aaea2..bb96884 100644 --- a/images/7.0-apache/Dockerfile +++ b/images/7.0-apache/Dockerfile @@ -72,11 +72,7 @@ RUN \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/7.0-fpm/Dockerfile b/images/7.0-fpm/Dockerfile index df9029b..4ed89d1 100644 --- a/images/7.0-fpm/Dockerfile +++ b/images/7.0-fpm/Dockerfile @@ -72,11 +72,7 @@ RUN \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/7.1-apache/Dockerfile b/images/7.1-apache/Dockerfile index ad894f5..1f6eedf 100644 --- a/images/7.1-apache/Dockerfile +++ b/images/7.1-apache/Dockerfile @@ -75,11 +75,7 @@ RUN \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/7.1-fpm/Dockerfile b/images/7.1-fpm/Dockerfile index 63e8beb..d015777 100644 --- a/images/7.1-fpm/Dockerfile +++ b/images/7.1-fpm/Dockerfile @@ -75,11 +75,7 @@ RUN \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/7.2-apache/Dockerfile b/images/7.2-apache/Dockerfile index e5579af..e30bd8e 100644 --- a/images/7.2-apache/Dockerfile +++ b/images/7.2-apache/Dockerfile @@ -73,11 +73,7 @@ RUN \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/7.2-fpm/Dockerfile b/images/7.2-fpm/Dockerfile index 6527340..b6338c8 100644 --- a/images/7.2-fpm/Dockerfile +++ b/images/7.2-fpm/Dockerfile @@ -73,11 +73,7 @@ RUN \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=1.10.27 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ - && su -c "composer global require -n hirak/prestissimo" -s /bin/sh www-data \ && apt-get -y clean \ && apt-get -y autoclean \ && apt-get -y autoremove \ diff --git a/images/7.3-apache/Dockerfile b/images/7.3-apache/Dockerfile index 9960eeb..add1cb5 100644 --- a/images/7.3-apache/Dockerfile +++ b/images/7.3-apache/Dockerfile @@ -69,9 +69,6 @@ RUN mkdir -p /usr/share/man/man1 /usr/share/man/man7 \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=2.2.24 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ && apt-get -y autoclean \ diff --git a/images/7.3-fpm/Dockerfile b/images/7.3-fpm/Dockerfile index 9d9ce35..ced55e9 100644 --- a/images/7.3-fpm/Dockerfile +++ b/images/7.3-fpm/Dockerfile @@ -69,9 +69,6 @@ RUN mkdir -p /usr/share/man/man1 /usr/share/man/man7 \ intl \ gettext \ pcntl \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php --install-dir=/usr/local/bin --filename=composer --version=2.2.24 \ - && php -r "unlink('composer-setup.php');" \ && chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ && apt-get -y autoclean \ diff --git a/images/7.4-apache/Dockerfile b/images/7.4-apache/Dockerfile index 74f375c..d6e28ad 100644 --- a/images/7.4-apache/Dockerfile +++ b/images/7.4-apache/Dockerfile @@ -59,8 +59,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2.2.24 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/7.4-fpm/Dockerfile b/images/7.4-fpm/Dockerfile index 9db7901..b8f9b7d 100644 --- a/images/7.4-fpm/Dockerfile +++ b/images/7.4-fpm/Dockerfile @@ -59,8 +59,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2.2.24 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.0-apache/Dockerfile b/images/8.0-apache/Dockerfile index 8447d27..16982d9 100644 --- a/images/8.0-apache/Dockerfile +++ b/images/8.0-apache/Dockerfile @@ -59,8 +59,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2.2.24 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.0-fpm/Dockerfile b/images/8.0-fpm/Dockerfile index 1c1c006..60e348a 100644 --- a/images/8.0-fpm/Dockerfile +++ b/images/8.0-fpm/Dockerfile @@ -59,8 +59,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2.2.24 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.1-apache/Dockerfile b/images/8.1-apache/Dockerfile index f94d48f..f8b79c6 100644 --- a/images/8.1-apache/Dockerfile +++ b/images/8.1-apache/Dockerfile @@ -57,8 +57,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.1-fpm/Dockerfile b/images/8.1-fpm/Dockerfile index 91c0cff..4f60dd2 100644 --- a/images/8.1-fpm/Dockerfile +++ b/images/8.1-fpm/Dockerfile @@ -57,8 +57,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.2-apache/Dockerfile b/images/8.2-apache/Dockerfile index ca9b33f..014f986 100644 --- a/images/8.2-apache/Dockerfile +++ b/images/8.2-apache/Dockerfile @@ -57,8 +57,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.2-fpm/Dockerfile b/images/8.2-fpm/Dockerfile index be633a0..ff83f30 100644 --- a/images/8.2-fpm/Dockerfile +++ b/images/8.2-fpm/Dockerfile @@ -57,8 +57,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.3-apache/Dockerfile b/images/8.3-apache/Dockerfile index 7780dc9..ab5e765 100644 --- a/images/8.3-apache/Dockerfile +++ b/images/8.3-apache/Dockerfile @@ -68,8 +68,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.3-fpm/Dockerfile b/images/8.3-fpm/Dockerfile index a327a81..f0fd1b0 100644 --- a/images/8.3-fpm/Dockerfile +++ b/images/8.3-fpm/Dockerfile @@ -69,8 +69,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.4-apache/Dockerfile b/images/8.4-apache/Dockerfile index 4aee8bf..c4cec88 100644 --- a/images/8.4-apache/Dockerfile +++ b/images/8.4-apache/Dockerfile @@ -70,8 +70,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/images/8.4-fpm/Dockerfile b/images/8.4-fpm/Dockerfile index 4d829a8..c9df85b 100644 --- a/images/8.4-fpm/Dockerfile +++ b/images/8.4-fpm/Dockerfile @@ -71,8 +71,6 @@ RUN \ RUN install-php-extensions xdebug \ && rm -f /usr/local/etc/php/conf.d/*xdebug.ini -RUN install-php-extensions @composer-2 - RUN \ chsh -s /bin/bash www-data && mkdir -p /var/www/.composer && chown -R www-data:www-data /var/www \ && apt-get -y clean \ diff --git a/utils/add-build-step.js b/utils/add-build-step.js index e244085..e8f3e56 100644 --- a/utils/add-build-step.js +++ b/utils/add-build-step.js @@ -3,9 +3,23 @@ // Modules const _ = require('lodash'); -/* - * Helper to get global deps - * @TODO: this looks pretty testable? should services have libs? +/** + * Helper function to add build steps to a service's configuration + * + * @param {string|string[]} steps - The build step(s) to add + * @param {Object} app - The Lando app object + * @param {string} name - The name of the service + * @param {string} [step='build_internal'] - The build step type to modify + * @param {boolean} [front=false] - Whether to add steps to front of array + * @return {void} - Modifies app config object directly + * + * @example + * // Add a build step to the end + * addBuildStep('npm install', app, 'web'); + * + * @example + * // Add multiple build steps to the front + * addBuildStep(['composer install', 'npm install'], app, 'web', 'build_internal', true); */ module.exports = (steps, app, name, step = 'build_internal', front = false) => { const current = _.get(app, `config.services.${name}.${step}`, []); diff --git a/utils/get-install-commands.js b/utils/get-install-commands.js index 506bece..30b06da 100644 --- a/utils/get-install-commands.js +++ b/utils/get-install-commands.js @@ -3,9 +3,25 @@ // Modules const _ = require('lodash'); -/* - * Helper to get global deps - * @TODO: this looks pretty testable? should services have libs? +/** + * Helper function to generate installation commands for dependencies + * + * @param {Object} deps - Dependencies object with package names as keys and versions as values + * @param {Function} pkger - Function that generates package installation command + * @param {string[]} [prefix=[]] - Command prefix to prepend to each installation command + * @return {string[]} Array of formatted installation commands + * + * @example + * // Generate npm install commands + * const deps = { 'lodash': '^4.0.0', 'express': '4.17.1' }; + * const npmInstall = (pkg, version) => ['npm', 'install', `${pkg}@${version}`]; + * getInstallCommands(deps, npmInstall); + * // Returns: ['npm install lodash@^4.0.0', 'npm install express@4.17.1'] + * + * @example + * // Generate commands with prefix + * getInstallCommands(deps, npmInstall, ['sudo', '-E']); + * // Returns: ['sudo -E npm install lodash@^4.0.0', 'sudo -E npm install express@4.17.1'] */ module.exports = (deps, pkger, prefix = []) => _(deps) .map((version, pkg) => _.flatten([prefix, pkger(pkg, version)]))