diff --git a/README.md b/README.md index 58fc04f..764491a 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,7 @@ COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr RUN install-php-extensions gd xdebug ``` -`install-php-extensions` will install all the required APT packages. -If you want to remove the APT development packages (which shouldn't be needed after the PHP extensions have been installed) and other no longer required packages, you can use the `--cleanup` option (**EXPERIMENTAL**): -``` -install-php-extensions --cleanup gd xdebug -``` +`install-php-extensions` will install all the required APT/APK packages; at the end of the script execution, the no-more needed packages will be removed. ## Supported PHP extensions diff --git a/install-php-extensions b/install-php-extensions index dd0801f..4dec79a 100755 --- a/install-php-extensions +++ b/install-php-extensions @@ -18,6 +18,29 @@ resetIFS () { ' } +# Get the distribution name +# +# Output: +# alpine|debian +getDistro () { + getDistro_os_id='' + if test -r /etc/os-release; then + getDistro_os_id="$(cat /etc/os-release | grep -E ^ID= | cut -d = -f 2)" + case "$getDistro_os_id" in + alpine|debian) + ;; + *) + getDistro_os_id='' + ;; + esac + fi + if test -n "$getDistro_os_id"; then + printf '%s' "$getDistro_os_id" + else + printf '%s' 'debian' + fi +} + # Get the PHP Major-Minor version as an integer value, in format MMmm (example: 506 for PHP 5.6.15) # # Output: @@ -36,33 +59,33 @@ getPHPInstalledModules () { ' for getPHPInstalledModules_module in $(php -m); do getPHPInstalledModules_moduleNormalized='' - case "${getPHPInstalledModules_module}" in + case "$getPHPInstalledModules_module" in \[PHP\ Modules\]) ;; \[Zend\ Modules\]) break ;; Core|PDO|PDO_*|Phar|Reflection|SimpleXML|SPL|SQLite|Xdebug) - getPHPInstalledModules_moduleNormalized=$(LC_CTYPE=C printf '%s' "${getPHPInstalledModules_module}" | tr '[:upper:]' '[:lower:]') + getPHPInstalledModules_moduleNormalized=$(LC_CTYPE=C printf '%s' "$getPHPInstalledModules_module" | tr '[:upper:]' '[:lower:]') ;; Zend\ OPcache) getPHPInstalledModules_moduleNormalized='opcache' ;; *\ *|*A*|*B*|*C*|*D*|*E*|*F*|*G*|*H*|*I*|*J*|*K*|*L*|*M*|*N*|*O*|*P*|*Q*|*R*|*S*|*T*|*U*|*V*|*W*|*X*|*Y*|*Z*) - printf '### WARNING Unrecognized module name: %s ###\n' "${getPHPInstalledModules_module}" >&2 + printf '### WARNING Unrecognized module name: %s ###\n' "$getPHPInstalledModules_module" >&2 ;; *) - getPHPInstalledModules_moduleNormalized="${getPHPInstalledModules_module}" + getPHPInstalledModules_moduleNormalized="$getPHPInstalledModules_module" ;; esac - if test -n "${getPHPInstalledModules_moduleNormalized}"; then - if ! stringInList "${getPHPInstalledModules_moduleNormalized}" "${getPHPInstalledModules_result}"; then - getPHPInstalledModules_result="${getPHPInstalledModules_result} ${getPHPInstalledModules_moduleNormalized}" + if test -n "$getPHPInstalledModules_moduleNormalized"; then + if ! stringInList "$getPHPInstalledModules_moduleNormalized" "$getPHPInstalledModules_result"; then + getPHPInstalledModules_result="$getPHPInstalledModules_result $getPHPInstalledModules_moduleNormalized" fi fi done resetIFS - printf '%s' "${getPHPInstalledModules_result}" + printf '%s' "${getPHPInstalledModules_result# }" } # Get the handles of the modules to be installed @@ -71,48 +94,47 @@ getPHPInstalledModules () { # $@: all module handles # # Set: -# DO_APT_REMOVE # PHP_MODULES_TO_INSTALL # # Output: # Nothing -getModulesToInstall () { - getModulesToInstall_alreadyInstalled="$(getPHPInstalledModules)" - getModulesToInstall_endArgs='' - DO_APT_REMOVE='' +processCommandArguments () { + processCommandArguments_alreadyInstalled="$(getPHPInstalledModules)" + processCommandArguments_endArgs=0 PHP_MODULES_TO_INSTALL='' while :; do if test $# -lt 1; then break fi - getModulesToInstall_skip='' - if test -z "${getModulesToInstall_endArgs}"; then - case "${1}" in + processCommandArguments_skip=0 + if test $processCommandArguments_endArgs -eq 0; then + case "$1" in --cleanup) - getModulesToInstall_skip='y' - DO_APT_REMOVE='y' + printf '### WARNING the --cleanup option is deprecated (we always cleanup everything) ###\n' "$1" >&2 + processCommandArguments_skip=1 ;; --) - getModulesToInstall_skip='y' - getModulesToInstall_endArgs='y' + processCommandArguments_skip=1 + processCommandArguments_endArgs=1 ;; -*) - printf 'Unrecognized option: %s\n' "${1}" >&2 + printf 'Unrecognized option: %s\n' "$1" >&2 exit 1 ;; esac fi - if test -z "${getModulesToInstall_skip}"; then - if stringInList "${1}" "${PHP_MODULES_TO_INSTALL}"; then - printf '### WARNING Duplicated module name specified: %s ###\n' "${1}" >&2 - elif stringInList "${1}" "${getModulesToInstall_alreadyInstalled}"; then - printf '### WARNING Module already installed: %s ###\n' "${1}" >&2 + if test $processCommandArguments_skip -eq 0; then + if stringInList "$1" "$PHP_MODULES_TO_INSTALL"; then + printf '### WARNING Duplicated module name specified: %s ###\n' "$1" >&2 + elif stringInList "$1" "$processCommandArguments_alreadyInstalled"; then + printf '### WARNING Module already installed: %s ###\n' "$1" >&2 else - PHP_MODULES_TO_INSTALL="${PHP_MODULES_TO_INSTALL} ${1}" + PHP_MODULES_TO_INSTALL="$PHP_MODULES_TO_INSTALL $1" fi fi shift done + PHP_MODULES_TO_INSTALL="${PHP_MODULES_TO_INSTALL# }" } # Sort the modules to be installed, in order to fix dependencies @@ -123,16 +145,16 @@ getModulesToInstall () { # Output: # Nothing sortModulesToInstall () { - if stringInList 'igbinary' "${PHP_MODULES_TO_INSTALL}"; then - PHP_MODULES_TO_INSTALL="$(removeStringFromList 'igbinary' "${PHP_MODULES_TO_INSTALL}")" + if stringInList 'igbinary' "$PHP_MODULES_TO_INSTALL"; then + PHP_MODULES_TO_INSTALL="$(removeStringFromList 'igbinary' "$PHP_MODULES_TO_INSTALL")" if test -z "$PHP_MODULES_TO_INSTALL"; then PHP_MODULES_TO_INSTALL='igbinary' else PHP_MODULES_TO_INSTALL="igbinary $PHP_MODULES_TO_INSTALL" fi fi - if stringInList 'msgpack' "${PHP_MODULES_TO_INSTALL}"; then - PHP_MODULES_TO_INSTALL="$(removeStringFromList 'msgpack' "${PHP_MODULES_TO_INSTALL}")" + if stringInList 'msgpack' "$PHP_MODULES_TO_INSTALL"; then + PHP_MODULES_TO_INSTALL="$(removeStringFromList 'msgpack' "$PHP_MODULES_TO_INSTALL")" if test -z "$PHP_MODULES_TO_INSTALL"; then PHP_MODULES_TO_INSTALL='msgpack' else @@ -141,175 +163,295 @@ sortModulesToInstall () { fi } -# Get the required APT packages for a specific PHP version and for the list of module handles +# Get the required APT/APK packages for a specific PHP version and for the list of module handles # # Arguments: # $1: the numeric PHP Major-Minor version # $@: the PHP module handles # -# Output: -# Space-separated list of APT packages -getRequiredAptPackages () { - getRequiredAptPackages_result='' - getRequiredAptPackages_phpv=${1} +# Set: +# PACKAGES_PERSISTENT +# PACKAGES_VOLATILE +# +# Return: +# 0 (true): if we to install some package +# 1 (false): if no package is required +buildRequiredPackageLists () { + buildRequiredPackageLists_persistent='' + buildRequiredPackageLists_volatile='' + buildRequiredPackageLists_distro="$(getDistro)" + buildRequiredPackageLists_phpv=$1 while :; do if test $# -lt 2; then break fi shift - case "${1}" in - amqp) - getRequiredAptPackages_result="${getRequiredAptPackages_result} librabbitmq-dev libssh-dev" + case "$1@$buildRequiredPackageLists_distro" in + amqp@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent rabbitmq-c" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile $PHPIZE_DEPS rabbitmq-c-dev" ;; - bz2) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libbz2-dev" + amqp@debian) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent librabbitmq4" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile librabbitmq-dev libssh-dev" ;; - cmark) - getRequiredAptPackages_result="${getRequiredAptPackages_result} cmake" + apcu@alpine) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile autoconf g++ make" ;; - enchant) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libenchant-dev" + bz2@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libbz2" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile bzip2-dev" ;; - gd) - if test $getRequiredAptPackages_phpv -lt 700; then - getRequiredAptPackages_result="${getRequiredAptPackages_result} libvpx-dev libjpeg62-turbo-dev libpng-dev libxpm-dev libfreetype6-dev" + bz2@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libbz2-dev" + ;; + cmark@alpine) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile cmake make g++ autoconf" + ;; + cmark@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile cmake" + ;; + enchant@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent enchant" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile enchant-dev" + ;; + enchant@debian) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libenchant1c2a" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libenchant-dev" + ;; + gd@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent freetype libjpeg-turbo libpng libxpm" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile freetype-dev libjpeg-turbo-dev libpng-dev libxpm-dev" + if test $buildRequiredPackageLists_phpv -le 506; then + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libvpx" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libvpx-dev" else - getRequiredAptPackages_result="${getRequiredAptPackages_result} libwebp-dev libjpeg62-turbo-dev libpng-dev libxpm-dev libfreetype6-dev" + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libwebp" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libwebp-dev" fi ;; - gmp) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libgmp-dev" + gd@debian) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libfreetype6 libjpeg62-turbo libpng16-16 libxpm4" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libfreetype6-dev libjpeg62-turbo-dev libpng-dev libxpm-dev" + if test $buildRequiredPackageLists_phpv -le 506; then + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libvpx?" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libvpx-dev" + else + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libwebp6" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libwebp-dev" + fi ;; - imap) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libc-client-dev libkrb5-dev" + gettext@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libintl" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile gettext-dev" ;; - interbase) - getRequiredAptPackages_result="${getRequiredAptPackages_result} firebird-dev libib-util" + gmp@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent gmp" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile gmp-dev" ;; - imagick) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libmagickwand-dev" + gmp@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libgmp-dev" ;; - intl) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libicu-dev" + igbinary@alpine) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile autoconf g++ make" ;; - ldap) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libldap2-dev" + imagick@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent imagemagick" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile imagemagick-dev autoconf g++ make re2c" ;; - memcache) - getRequiredAptPackages_result="${getRequiredAptPackages_result} zlib1g-dev" + imagick@debian) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libmagickwand-6.q16-?" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libmagickwand-dev" ;; - memcached) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libmemcached-dev zlib1g-dev" + imap@alpine) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent c-client" + if test -z "$(apk info | grep -E ^libssl)"; then + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libssl1.0" + fi + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile krb5-dev imap-dev openssl openssl-dev" ;; - mcrypt) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libmcrypt-dev" + imap@debian) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libc-client2007e" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libc-client-dev libkrb5-dev" ;; - mssql) - getRequiredAptPackages_result="${getRequiredAptPackages_result} freetds-dev" + + interbase@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile firebird-dev libib-util" ;; - odbc) - getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + intl@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libicu-dev" ;; - pdo_dblib) - getRequiredAptPackages_result="${getRequiredAptPackages_result} freetds-dev" + ldap@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libldap2-dev" ;; - pdo_firebird) - getRequiredAptPackages_result="${getRequiredAptPackages_result} firebird-dev libib-util" + memcache@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile zlib1g-dev" ;; - pdo_pgsql) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libpq-dev" + memcached@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libmemcached-dev zlib1g-dev" ;; - pdo_odbc) - getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + mcrypt@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libmcrypt-dev" ;; - pdo_sqlsrv) - getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + mssql@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile freetds-dev" ;; - pgsql) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libpq-dev" + odbc@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile unixodbc-dev" ;; - pspell) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libpspell-dev" + pdo_dblib@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile freetds-dev" ;; - recode) - getRequiredAptPackages_result="${getRequiredAptPackages_result} librecode-dev" + pdo_firebird@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile firebird-dev libib-util" ;; - ssh2) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libssh2-1-dev" + pdo_pgsql@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libpq-dev" ;; - snmp) - getRequiredAptPackages_result="${getRequiredAptPackages_result} snmp libsnmp-dev" + pdo_odbc@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile unixodbc-dev" ;; - soap) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libxml2-dev" + pdo_sqlsrv@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile unixodbc-dev" ;; - solr) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libcurl4-gnutls-dev libxml2-dev" + pgsql@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libpq-dev" ;; - sqlsrv) - getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + pspell@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libpspell-dev" ;; - sybase_ct) - getRequiredAptPackages_result="${getRequiredAptPackages_result} freetds-dev" + recode@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile librecode-dev" ;; - tidy) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libtidy-dev" + ssh2@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libssh2-1-dev" ;; - uuid) - getRequiredAptPackages_result="${getRequiredAptPackages_result} uuid-dev" + snmp@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile snmp libsnmp-dev" ;; - wddx) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libxml2-dev" + soap@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libxml2-dev" ;; - xmlrpc) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libxml2-dev" + solr@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libcurl4-gnutls-dev libxml2-dev" ;; - xsl) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libxslt-dev" + sqlsrv@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile unixodbc-dev" ;; - yaml) - getRequiredAptPackages_result="${getRequiredAptPackages_result} libyaml-dev" + sybase_ct@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile freetds-dev" ;; - zip) - getRequiredAptPackages_result="${getRequiredAptPackages_result} cmake zlib1g-dev libbz2-dev libmbedtls-dev" + tidy@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libtidy-dev" + ;; + uuid@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile uuid-dev" + ;; + wddx@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libxml2-dev" + ;; + xmlrpc@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libxml2-dev" + ;; + xsl@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libxslt-dev" + ;; + yaml@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libyaml-dev" + ;; + zip@debian) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile cmake zlib1g-dev libbz2-dev libmbedtls-dev" ;; esac done - printf '%s' "${getRequiredAptPackages_result}" + PACKAGES_PERSISTENT='' + PACKAGES_VOLATILE='' + if test -z "$buildRequiredPackageLists_persistent$buildRequiredPackageLists_volatile"; then + return 0 + fi + case "$buildRequiredPackageLists_distro" in + alpine) + apk update + ;; + debian) + DEBIAN_FRONTEND=noninteractive apt-get update + DEBIAN_FRONTEND=noninteractive apt-get autoremove --purge -y + ;; + esac + if test -n "$buildRequiredPackageLists_persistent"; then + PACKAGES_PERSISTENT="$(expandPackagesToBeInstalled $buildRequiredPackageLists_persistent)" + fi + if test -n "$buildRequiredPackageLists_volatile"; then + resetIFS + for buildRequiredPackageLists_package in $(expandPackagesToBeInstalled $buildRequiredPackageLists_volatile); do + if ! stringInList "$buildRequiredPackageLists_package" "$PACKAGES_PERSISTENT"; then + PACKAGES_VOLATILE="$PACKAGES_VOLATILE $buildRequiredPackageLists_package" + fi + done + PACKAGES_VOLATILE="${PACKAGES_VOLATILE# }" + fi } -# Get the newly installed APT packages that will be no more needed after the installation of PHP extensions +# Get the full list of APT/APK packages that will be installed, given the required packages # # Arguments: -# $1: the list of APT packages that will be installed +# $1: the list of required APT/APK packages # # Output: -# Space-separated list of APT packages to be removed -getAptPackagesToRemove () { - getAptPackagesToRemove_inNewPackages='' - getAptPackagesToRemove_result='' - IFS=' +# Space-separated list of every APT/APK packages that will be installed +expandPackagesToBeInstalled () { + expandPackagesToBeInstalled_result='' + case "$(getDistro)" in + alpine) + IFS=' ' - for getAptPackagesToRemove_aptLine in $(DEBIAN_FRONTEND=noninteractive apt-get install -sy $@); do - if test -z "${getAptPackagesToRemove_inNewPackages}"; then - if test "${getAptPackagesToRemove_aptLine}" = 'The following NEW packages will be installed:'; then - getAptPackagesToRemove_inNewPackages='y' - resetIFS - fi - elif test "${getAptPackagesToRemove_aptLine}" = "${getAptPackagesToRemove_aptLine# }"; then - getAptPackagesToRemove_inNewPackages='' - else - for getAptPackagesToRemove_newPackage in ${getAptPackagesToRemove_aptLine}; do - case "${getAptPackagesToRemove_newPackage}" in - *-dev|cmake|cmake-data) - getAptPackagesToRemove_result="${getAptPackagesToRemove_result} ${getAptPackagesToRemove_newPackage}" - ;; - esac + for expandPackagesToBeInstalled_line in $(apk add --simulate $@); do + if test -n "$(printf '%s' "$expandPackagesToBeInstalled_line" | grep -E '^\([0-9]*/[0-9]*) Installing ')"; then + expandPackagesToBeInstalled_result="$expandPackagesToBeInstalled_result $(printf '%s' "$expandPackagesToBeInstalled_line" | cut -d ' ' -f 3)" + fi done - fi - done - resetIFS - printf '%s' "${getAptPackagesToRemove_result}" + resetIFS + ;; + debian) + expandPackagesToBeInstalled_inNewPackages=0 + IFS=' +' + for expandPackagesToBeInstalled_line in $(DEBIAN_FRONTEND=noninteractive apt-get install -sy $@); do + if test $expandPackagesToBeInstalled_inNewPackages -eq 0; then + if test "$expandPackagesToBeInstalled_line" = 'The following NEW packages will be installed:'; then + expandPackagesToBeInstalled_inNewPackages=1 + fi + elif test "$expandPackagesToBeInstalled_line" = "${expandPackagesToBeInstalled_line# }"; then + break + else + resetIFS + for expandPackagesToBeInstalled_newPackage in $expandPackagesToBeInstalled_line; do + expandPackagesToBeInstalled_result="$expandPackagesToBeInstalled_result $expandPackagesToBeInstalled_newPackage" + done + IFS=' +' + fi + done + resetIFS + ;; + esac + printf '%s' "${expandPackagesToBeInstalled_result# }" +} + +# Install the required APT/APK packages +# +# Arguments: +# $@: the list of APT/APK packages to be installed +installRequiredPackages () { + printf '### INSTALLING REQUIRED PACKAGES ###\n' + case "$(getDistro)" in + alpine) + apk add $PACKAGES_PERSISTENT $PACKAGES_VOLATILE + ;; + debian) + DEBIAN_FRONTEND=noninteractive apt-get install -y $PACKAGES_PERSISTENT $PACKAGES_VOLATILE + ;; + esac } # Install a bundled PHP module given its handle @@ -319,20 +461,20 @@ getAptPackagesToRemove () { # $2: the handle of the PHP module # # Set: -# UNNEEDED_APT_PACKAGE_LINKS +# UNNEEDED_PACKAGE_LINKS # # Output: # Nothing installBundledModule () { - printf '### INSTALLING BUNDLED MODULE %s ###\n' "${2}" - case "${2}" in + printf '### INSTALLING BUNDLED MODULE %s ###\n' "$2" + case "$2" in gd) if test $1 -le 506; then - docker-php-ext-configure gd --with-gd --with-vpx-dir --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --enable-gd-native-ttf + docker-php-ext-configure gd --with-gd --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --enable-gd-native-ttf --with-vpx-dir elif test $1 -le 701; then - docker-php-ext-configure gd --with-gd --with-webp-dir --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --enable-gd-native-ttf + docker-php-ext-configure gd --with-gd --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --enable-gd-native-ttf --with-webp-dir elif test $1 -le 703; then - docker-php-ext-configure gd --with-gd --with-webp-dir --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir + docker-php-ext-configure gd --with-gd --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --with-webp-dir else docker-php-ext-configure gd --enable-gd --with-webp --with-jpeg --with-xpm --with-freetype fi @@ -342,7 +484,7 @@ installBundledModule () { 506) if ! test -f /usr/include/gmp.h; then ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h - UNNEEDED_APT_PACKAGE_LINKS="${UNNEEDED_APT_PACKAGE_LINKS} /usr/include/gmp.h" + UNNEEDED_PACKAGE_LINKS="$UNNEEDED_PACKAGE_LINKS /usr/include/gmp.h" fi ;; esac @@ -358,7 +500,7 @@ installBundledModule () { 506|700|701|702|703|704) if ! test -f /usr/lib/libsybdb.so; then ln -s /usr/lib/x86_64-linux-gnu/libsybdb.so /usr/lib/libsybdb.so - UNNEEDED_APT_PACKAGE_LINKS="${UNNEEDED_APT_PACKAGE_LINKS} /usr/lib/libsybdb.so" + UNNEEDED_PACKAGE_LINKS="$UNNEEDED_PACKAGE_LINKS /usr/lib/libsybdb.so" fi ;; esac @@ -395,7 +537,7 @@ installBundledModule () { fi ;; esac - docker-php-ext-install -j$(nproc) "${2}" + docker-php-ext-install -j$(nproc) "$2" } # Fetch a tar.gz file, extract it and returns the path of the extracted folder. @@ -408,24 +550,24 @@ installBundledModule () { getPackageSource () { mkdir -p /tmp/src getPackageSource_tempFile=$(mktemp -p /tmp/src) - curl -L -s -S -o "${getPackageSource_tempFile}" "$1" + curl -L -s -S -o "$getPackageSource_tempFile" "$1" getPackageSource_tempDir=$(mktemp -p /tmp/src -d) - cd "${getPackageSource_tempDir}" - tar -xzf "${getPackageSource_tempFile}" + cd "$getPackageSource_tempDir" + tar -xzf "$getPackageSource_tempFile" cd - >/dev/null - unlink "${getPackageSource_tempFile}" + unlink "$getPackageSource_tempFile" getPackageSource_outDir='' - for getPackageSource_i in $(ls "${getPackageSource_tempDir}"); do - if test -n "${getPackageSource_outDir}" || test -f "${getPackageSource_tempDir}/${getPackageSource_i}"; then + for getPackageSource_i in $(ls "$getPackageSource_tempDir"); do + if test -n "$getPackageSource_outDir" || test -f "$getPackageSource_tempDir/$getPackageSource_i"; then getPackageSource_outDir='' break fi - getPackageSource_outDir="${getPackageSource_tempDir}/${getPackageSource_i}" + getPackageSource_outDir="$getPackageSource_tempDir/$getPackageSource_i" done - if test -n "${getPackageSource_outDir}"; then - printf '%s' "${getPackageSource_outDir}" + if test -n "$getPackageSource_outDir"; then + printf '%s' "$getPackageSource_outDir" else - printf '%s' "${getPackageSource_tempDir}" + printf '%s' "$getPackageSource_tempDir" fi } @@ -437,14 +579,14 @@ getPackageSource () { # $3: the options of the configure command # $4: the value of CFLAGS installModuleFromSource () { - printf '### INSTALLING MODULE %s FROM SOURCE CODE ###\n' "${1}" - installModuleFromSource_dir="$(getPackageSource "${2}")" - cd "${installModuleFromSource_dir}" + printf '### INSTALLING MODULE %s FROM SOURCE CODE ###\n' "$1" + installModuleFromSource_dir="$(getPackageSource "$2")" + cd "$installModuleFromSource_dir" phpize - ./configure ${3} CFLAGS="${4:-}" + ./configure $3 CFLAGS="${4:-}" make -j$(nproc) install cd -- - docker-php-ext-enable "${1}" + docker-php-ext-enable "$1" } # Install a PECL PHP module given its handle @@ -453,18 +595,18 @@ installModuleFromSource () { # $1: the numeric PHP Major-Minor version # $2: the handle of the PHP module installPECLModule () { - printf '### INSTALLING PECL MODULE %s ###\n' "${2}" - installPECLModule_actual="${2}" + printf '### INSTALLING PECL MODULE %s ###\n' "$2" + installPECLModule_actual="$2" installPECLModule_stdin='\n' - case "${2}" in + case "$2" in apcu) if test $1 -le 506; then - installPECLModule_actual="${2}-4.0.11" + installPECLModule_actual="$2-4.0.11" fi ;; memcached) if test $1 -lt 700; then - installPECLModule_actual="${2}-2.2.0" + installPECLModule_actual="$2-2.2.0" # --with-libmemcached-dir (default: no) Set the path to libmemcached install prefix else installPECLModule_stdin='' @@ -490,47 +632,47 @@ installPECLModule () { ;; msgpack) if test $1 -le 506; then - installPECLModule_actual="${2}-0.5.7" + installPECLModule_actual="$2-0.5.7" fi ;; parallel) if test $1 -le 701; then - installPECLModule_actual="${2}-0.8.3" + installPECLModule_actual="$2-0.8.3" fi ;; pcov) if test $1 -lt 701; then - installPECLModule_actual="${2}-0.9.0" + installPECLModule_actual="$2-0.9.0" fi ;; pdo_sqlsrv | sqlsrv) # https://docs.microsoft.com/it-it/sql/connect/php/system-requirements-for-the-php-sql-driver?view=sql-server-2017 if test $1 -le 700; then - installPECLModule_actual="${2}-5.3.0" + installPECLModule_actual="$2-5.3.0" elif test $1 -ge 704; then - installPECLModule_actual="${2}-5.7.0preview" + installPECLModule_actual="$2-5.7.0preview" fi ;; pthreads) if test $1 -lt 700; then - installPECLModule_actual="${2}-2.0.10" + installPECLModule_actual="$2-2.0.10" fi ;; redis) if test $1 -le 506; then - installPECLModule_actual="${2}-4.3.0" + installPECLModule_actual="$2-4.3.0" fi # enable-redis-igbinary? enable-redis-lzf? php --ri igbinary >/dev/null 2>/dev/null && installPECLModule_stdin='yes\nyes\n' || installPECLModule_stdin='no\nyes\n' ;; solr) if test $1 -le 506; then - installPECLModule_actual="${2}-2.4.0" + installPECLModule_actual="$2-2.4.0" fi ;; ssh2) if test $1 -le 506; then - installPECLModule_actual="${2}-0.13" + installPECLModule_actual="$2-0.13" else # see https://bugs.php.net/bug.php?id=78560 installPECLModule_actual='https://pecl.php.net/get/ssh2' @@ -538,35 +680,35 @@ installPECLModule () { ;; xdebug) if test $1 -lt 501; then - installPECLModule_actual="${2}-2.0.5" + installPECLModule_actual="$2-2.0.5" elif test $1 -lt 504; then - installPECLModule_actual="${2}-2.2.7" + installPECLModule_actual="$2-2.2.7" elif test $1 -lt 505; then - installPECLModule_actual="${2}-2.4.1" + installPECLModule_actual="$2-2.4.1" elif test $1 -lt 700; then - installPECLModule_actual="${2}-2.5.5" + installPECLModule_actual="$2-2.5.5" elif test $1 -ge 704; then - installPECLModule_actual="${2}-2.8.0beta2" + installPECLModule_actual="$2-2.8.0beta2" fi ;; uopz) if test $1 -lt 700; then - installPECLModule_actual="${2}-2.0.7" + installPECLModule_actual="$2-2.0.7" elif test $1 -lt 701; then - installPECLModule_actual="${2}-5.0.2" + installPECLModule_actual="$2-5.0.2" fi ;; yaml) if test $1 -lt 700; then - installPECLModule_actual="${2}-1.3.1" + installPECLModule_actual="$2-1.3.1" fi ;; esac - if test "${2}" != "${installPECLModule_actual}"; then - printf ' (installing version %s)\n' "${installPECLModule_actual}" + if test "$2" != "$installPECLModule_actual"; then + printf ' (installing version %s)\n' "$installPECLModule_actual" fi - printf "${installPECLModule_stdin}" | pecl install "${installPECLModule_actual}" - docker-php-ext-enable "${2}" + printf "$installPECLModule_stdin" | pecl install "$installPECLModule_actual" + docker-php-ext-enable "$2" } # Check if a string is in a list of space-separated string @@ -579,8 +721,8 @@ installPECLModule () { # 0 (true): if the string is in the list # 1 (false): if the string is not in the list stringInList () { - for stringInList_listItem in ${2}; do - if test "${1}" = "${stringInList_listItem}"; then + for stringInList_listItem in $2; do + if test "$1" = "$stringInList_listItem"; then return 0 fi done @@ -597,8 +739,8 @@ stringInList () { # The list without the word removeStringFromList () { removeStringFromList_result='' - for removeStringFromList_listItem in ${2}; do - if test "${1}" != "${removeStringFromList_listItem}"; then + for removeStringFromList_listItem in $2; do + if test "$1" != "$removeStringFromList_listItem"; then if test -z "$removeStringFromList_result"; then removeStringFromList_result="$removeStringFromList_listItem" else @@ -606,84 +748,96 @@ removeStringFromList () { fi fi done - printf '%s' "${removeStringFromList_result}" + printf '%s' "$removeStringFromList_result" +} + +# Cleanup everything at the end of the execution +cleanup () { + cleanup_distro="$(getDistro)" + if test -n "$UNNEEDED_PACKAGE_LINKS"; then + printf '### REMOVING UNNEEDED PACKAGE LINKS ###\n' + for cleanup_link in $UNNEEDED_PACKAGE_LINKS; do + if test -L "$cleanup_link"; then + rm -f "$cleanup_link" + fi + done + fi + if test -n "$PACKAGES_VOLATILE"; then + printf '### REMOVING UNNEEDED PACKAGES ###\n' + case "$cleanup_distro" in + alpine) + apk del --purge $PACKAGES_VOLATILE + ;; + debian) + DEBIAN_FRONTEND=noninteractive apt-get remove --purge -y $PACKAGES_VOLATILE + ;; + esac + fi + case "$cleanup_distro" in + alpine) + rm -rf /var/cache/apk/* + ;; + debian) + rm -rf /var/lib/apt/lists/* + ;; + esac + docker-php-source delete + rm -rf /tmp/pear + rm -rf /tmp/src } resetIFS PHP_MAJMIN_VERSION=$(getPHPMajorMinor) -case "${PHP_MAJMIN_VERSION}" in +case "$PHP_MAJMIN_VERSION" in 506|700|701|702|703|704) ;; *) printf "### ERROR: Unsupported PHP version: %s.%s ###\n" $(( PHP_MAJMIN_VERSION / 100 )) $(( PHP_MAJMIN_VERSION % 100 )) esac -UNNEEDED_APT_PACKAGES='' -UNNEEDED_APT_PACKAGE_LINKS='' -getModulesToInstall "$@" -sortModulesToInstall +UNNEEDED_PACKAGE_LINKS='' +processCommandArguments "$@" -if test -n "${PHP_MODULES_TO_INSTALL}"; then - REQUIRED_APT_PACKAGES=$(getRequiredAptPackages ${PHP_MAJMIN_VERSION} ${PHP_MODULES_TO_INSTALL}) - if test -n "${REQUIRED_APT_PACKAGES}"; then - printf '### INSTALLING REQUIRED APT PACKAGES ###\n' - DEBIAN_FRONTEND=noninteractive apt-get update -y - if test -n "${DO_APT_REMOVE}"; then - UNNEEDED_APT_PACKAGES=$(getAptPackagesToRemove ${REQUIRED_APT_PACKAGES}) - fi - DEBIAN_FRONTEND=noninteractive apt-get install -y ${REQUIRED_APT_PACKAGES} - fi - docker-php-source extract - BUNDLED_MODULES="$(find /usr/src/php/ext -mindepth 2 -maxdepth 2 -type f -name 'config.m4' | xargs -n1 dirname | xargs -n1 basename | xargs)" - for PHP_MODULE_TO_INSTALL in ${PHP_MODULES_TO_INSTALL}; do - if stringInList "${PHP_MODULE_TO_INSTALL}" "${BUNDLED_MODULES}"; then - installBundledModule ${PHP_MAJMIN_VERSION} "${PHP_MODULE_TO_INSTALL}" - else - MODULE_SOURCE='' - MODULE_SOURCE_CONFIGOPTIONS='' - MODULE_SOURCE_CFLAGS='' - case "${PHP_MODULE_TO_INSTALL}" in - cmark) - MODULE_SOURCE=https://github.com/krakjoe/cmark/archive/v1.0.0.tar.gz - cd "$(getPackageSource https://github.com/commonmark/cmark/archive/0.28.3.tar.gz)" - make install - cd - - MODULE_SOURCE_CONFIGOPTIONS=--with-cmark - ;; - igbinary) - if test ${PHP_MAJMIN_VERSION} -lt 700; then - MODULE_SOURCE="https://github.com/igbinary/igbinary/archive/2.0.8.tar.gz" - else - MODULE_SOURCE="https://github.com/igbinary/igbinary/archive/3.0.1.tar.gz" - fi - MODULE_SOURCE_CONFIGOPTIONS=--enable-igbinary - MODULE_SOURCE_CFLAGS='-O2 -g' - ;; - esac - if test -n "${MODULE_SOURCE}"; then - installModuleFromSource "${PHP_MODULE_TO_INSTALL}" "${MODULE_SOURCE}" "${MODULE_SOURCE_CONFIGOPTIONS}" "${MODULE_SOURCE_CFLAGS}" - else - installPECLModule ${PHP_MAJMIN_VERSION} "${PHP_MODULE_TO_INSTALL}" - fi - fi - done - if test -n "${DO_APT_REMOVE}"; then - printf '### REMOVING NO LONGER REQUIRED PACKAGES ###\n' - DEBIAN_FRONTEND=noninteractive apt autoremove -y - fi - if test -n "${UNNEEDED_APT_PACKAGES}"; then - printf '### REMOVING UNNEEDED APT PACKAGES ###\n' - if test -n "${UNNEEDED_APT_PACKAGE_LINKS}"; then - for unneededAptPackageLink in ${UNNEEDED_APT_PACKAGE_LINKS}; do - if test -L "${unneededAptPackageLink}"; then - rm -f "${unneededAptPackageLink}" - fi - done - fi - DEBIAN_FRONTEND=noninteractive apt-get remove --purge -y ${UNNEEDED_APT_PACKAGES} - fi +if test -z "$PHP_MODULES_TO_INSTALL"; then + exit 0 fi -docker-php-source delete -rm -rf /tmp/pear -rm -rf /var/lib/apt/lists/* -rm -rf /tmp/src +sortModulesToInstall + +if buildRequiredPackageLists $PHP_MAJMIN_VERSION $PHP_MODULES_TO_INSTALL; then + installRequiredPackages +fi +docker-php-source extract +BUNDLED_MODULES="$(find /usr/src/php/ext -mindepth 2 -maxdepth 2 -type f -name 'config.m4' | xargs -n1 dirname | xargs -n1 basename | xargs)" +for PHP_MODULE_TO_INSTALL in $PHP_MODULES_TO_INSTALL; do + if stringInList "$PHP_MODULE_TO_INSTALL" "$BUNDLED_MODULES"; then + installBundledModule $PHP_MAJMIN_VERSION "$PHP_MODULE_TO_INSTALL" + else + MODULE_SOURCE='' + MODULE_SOURCE_CONFIGOPTIONS='' + MODULE_SOURCE_CFLAGS='' + case "$PHP_MODULE_TO_INSTALL" in + cmark) + MODULE_SOURCE=https://github.com/krakjoe/cmark/archive/v1.0.0.tar.gz + cd "$(getPackageSource https://github.com/commonmark/cmark/archive/0.28.3.tar.gz)" + make install + cd - + MODULE_SOURCE_CONFIGOPTIONS=--with-cmark + ;; + igbinary) + if test $PHP_MAJMIN_VERSION -lt 700; then + MODULE_SOURCE="https://github.com/igbinary/igbinary/archive/2.0.8.tar.gz" + else + MODULE_SOURCE="https://github.com/igbinary/igbinary/archive/3.0.1.tar.gz" + fi + MODULE_SOURCE_CONFIGOPTIONS=--enable-igbinary + MODULE_SOURCE_CFLAGS='-O2 -g' + ;; + esac + if test -n "$MODULE_SOURCE"; then + installModuleFromSource "$PHP_MODULE_TO_INSTALL" "$MODULE_SOURCE" "$MODULE_SOURCE_CONFIGOPTIONS" "$MODULE_SOURCE_CFLAGS" + else + installPECLModule $PHP_MAJMIN_VERSION "$PHP_MODULE_TO_INSTALL" + fi + fi +done +cleanup diff --git a/scripts/travisci-test-extensions b/scripts/travisci-test-extensions index bf48a99..ec76f36 100755 --- a/scripts/travisci-test-extensions +++ b/scripts/travisci-test-extensions @@ -69,7 +69,7 @@ testExtension () { testExtension_Image="$(getDockerImageName "${1}" "${2}")" printf ' - Docker image: %s\n' "${testExtension_Image}" testExtension_out=`mktemp` - if $(docker run --rm --volume "${TRAVIS_BUILD_DIR}:/app" --workdir /app "${testExtension_Image}" sh -c "./install-php-extensions --cleanup '${1}' && php ./scripts/check-installed-extension.php '${1}'" >"${testExtension_out}" 2>&1); then + if $(docker run --rm --volume "${TRAVIS_BUILD_DIR}:/app" --workdir /app "${testExtension_Image}" sh -c "./install-php-extensions '${1}' && php ./scripts/check-installed-extension.php '${1}'" >"${testExtension_out}" 2>&1); then rm -rf "${testExtension_out}" printf ' - Passed\n' return 0