diff --git a/bin/compile b/bin/compile index 7de8c5f0..7a9570e5 100755 --- a/bin/compile +++ b/bin/compile @@ -11,7 +11,6 @@ source $basedir/common.sh source $basedir/../lib/package source $basedir/../lib/composer source $basedir/../lib/datadog -source $basedir/../lib/scout source $basedir/../lib/newrelic source $basedir/../lib/apt source $basedir/../lib/pecl @@ -312,10 +311,6 @@ if [ -f "$BUILD_DIR/composer.json" ] && package_datadog_enabled; then install_datadog "${DATADOG_TRACER_VERSION}" "${DATADOG_APPSEC_VERSION}" fi -if [ -f "$BUILD_DIR/composer.json" ] && package_scout_enabled; then - install_scout "${SCOUT_APM_VERSION}" -fi - if [ -f "$BUILD_DIR/composer.json" ] && package_newrelic_enabled; then status "New Relic usage detected, installing Agent and PHP extension" LOG_FILES+=( "/app/vendor/newrelic/daemon.log" "/app/vendor/newrelic/agent.log" ) diff --git a/lib/composer b/lib/composer index e97a9419..b30c7c26 100644 --- a/lib/composer +++ b/lib/composer @@ -127,7 +127,7 @@ function install_composer_deps() { echo "Installing PHP extension: ${ext}" | indent fetch_package "${PHP_BASE_URL}" "${extension_package_path}" "/app/vendor/php" else - install_pecl_extension "${ext}" "${ext_version}" "${CACHE_DIR}" + php::pecl::install_extension "${ext}" "${ext_version}" "${CACHE_DIR}" fi done fi diff --git a/lib/pecl b/lib/pecl old mode 100644 new mode 100755 index cc06ae73..ae4345b4 --- a/lib/pecl +++ b/lib/pecl @@ -1,87 +1,317 @@ -function install_pecl_extension() { +#!/usr/bin/env bash + +function php::pecl::enable_extension() { + local rc=0 + local known_zend_extensions=("scoutapm") + + local name="${1}" + + local is_zend_extension_var_name + local is_zend_extension + local is_in_array + + is_zend_extension_var_name="PHP_PECL_EXTENSION_IS_ZEND_${name}" + + is_in_array="$( echo "${known_zend_extensions[@]}" | grep -ow "${name}" | wc -w )" + + if [ "${is_in_array}" -gt 0 ]; then + declare "${is_zend_extension_var_name}"="true" + export "${is_zend_extension_var_name?}" + fi + + is_zend_extension="$( printenv "${is_zend_extension_var_name}" )" + + if [[ "${is_zend_extension}" = "true" ]]; then + echo "zend_extension=${name}.so" \ + > "/app/vendor/php/etc/conf.d/${name}.ini" + else + echo "extension=${name}.so" \ + > "/app/vendor/php/etc/conf.d/${name}.ini" + fi + + return "${rc}" +} + + +function php::pecl::get_latest_version() { + local rc=1 + local extension_name="${1}" + + local version + local url="https://pecl.php.net/rest/r/${extension_name}/latest.txt" + + if version="$( curl --fail --silent --show-error --location "${url}" )"; then + echo -n "${version}" + rc=0 + fi + + return "${rc}" +} + + +function php::pecl::install_from_cache() { + local rc=1 + + local name="${1}" local version="${2}" local cache_dir="${3}" + local ext_dir="${4}" + + local cached_file - if [[ $version = '*' ]]; then - local version=$(curl --silent "https://pecl.php.net/rest/r/$extension_name/latest.txt") + cached_file="${cache_dir}/${name}-${version}.so" + + if [ -f "${cached_file}" ]; then + cp "${cached_file}" "${ext_dir}/${name}.so" + + php::pecl::enable_extension "${name}" + rc="${?}" fi - local ext_dir=/app/vendor/php/lib/php/extensions/no-debug-non-zts-$(php_api_version) - - local cache_extension_file="${cache_dir}/${extension_name}-${version}.so" - if [ -f "${cache_extension_file}" ]; then - echo "Installing PECL extension ${extension_name} version ${version} from the cache" | indent - cp "${cache_extension_file}" "${ext_dir}/${extension_name}.so" - enable_pecl_extension ${extension_name} - return + + return "${rc}" +} + + +function php::pecl::download_extension() { + local rc=1 + + local name="${1}" + local version="${2}" + local temp_dir="${3}" + + local archive + local url + + archive="${name}-${version}.tgz" + url="https://pecl.php.net/get/${archive}" + + pushd "${temp_dir}" >/dev/null \ + || { echo "Unable to enter ${temp_dir}." >&2; return 1; } + + curl --silent --location --fail "${url}" --output "${archive}" + rc="${?}" + + if [ "${rc}" -eq 0 ]; then + echo "${temp_dir}/${archive}" fi - local build_dir=$(pwd) - local temp_dir=$(mktmpdir "pecl-extension") + popd >/dev/null || return 1 - echo "Installing PECL extension ${extension_name} version ${version}" | indent + return "${rc}" +} - pushd "${temp_dir}" > /dev/null - curl --silent --location "https://pecl.php.net/get/${extension_name}-${version}.tgz" | tar xz +function php::pecl::extract_extension() { + local rc=1 - pushd ${extension_name}-${version} > /dev/null - ( - set +e - readonly phpize_log_file=$(mktemp "/tmp/pecl-phpize-${extension_name}-XXXX.log") - /app/vendor/php/bin/phpize > "${phpize_log_file}" 2>&1 - [ $? -eq 0 ] || install_pecl_error "${extension_name}" "package" "${phpize_log_file}" + local archive="${1}" + local output_dir="${2}" - local configure_extension_args_var_name="PHP_PECL_EXTENSION_CONFIGURE_ARGS_$extension_name" - local configure_extension_args=$(printenv $configure_extension_args_var_name) - local flags=$(echo $configure_extension_args | sed "s|\$BUILD_DIR|$build_dir|") + mkdir --parents "${output_dir}" - if [[ $extension_name = 'oci8' ]]; then - flags="--with-oci8=instantclient,${ORACLE_HOME}" - fi + tar --extract --gzip --strip-components=1 \ + --directory="${output_dir}" --file="${archive}" + + rc="${?}" + + if [ "${rc}" -ne 0 ]; then + rm --recursive --force "${archive}" + fi + + return "${rc}" +} + + +function php::pecl::package_extension() { + local rc=1 + + local name="${1}" + + local log - readonly configure_log_file=$(mktemp "/tmp/pecl-configure-${extension_name}-XXXX.log") - ./configure --with-php-config=/app/vendor/php/bin/php-config $flags > "${configure_log_file}" 2>&1 - [ $? -eq 0 ] || install_pecl_error "${extension_name}" "configure build" "${configure_log_file}" + log="$( mktemp "/tmp/pecl-phpize-${name}-XXXX.log" )" - readonly make_log_file=$(mktemp "/tmp/pecl-make-${extension_name}-XXXX.log") - make -j 2 > "${make_log_file}" 2>&1 - [ $? -eq 0 ] || install_pecl_error "${extension_name}" "compile" "${make_log_file}" - ) + /app/vendor/php/bin/phpize >"${log}" 2>&1 + rc="${?}" - cp modules/${extension_name}.so "${ext_dir}/${extension_name}.so" - cp modules/${extension_name}.so "${cache_extension_file}" - enable_pecl_extension ${extension_name} + echo -n "${log}" - popd > /dev/null - popd > /dev/null + return "${rc}" } -function enable_pecl_extension() { - local extension_name="${1}" - local is_zend_extension_var_name="PHP_PECL_EXTENSION_IS_ZEND_$extension_name" - local is_zend_extension=$(printenv $is_zend_extension_var_name) - if [[ $is_zend_extension = "true" ]] ; then - echo "zend_extension=${extension_name}.so" > "/app/vendor/php/etc/conf.d/${extension_name}.ini" - else - echo "extension=${extension_name}.so" > "/app/vendor/php/etc/conf.d/${extension_name}.ini" +function php::pecl::configure_extension() { + local rc=1 + + local name="${1}" + local build_dir="${2}" + + local log + local configure_args_varname + local configure_args + local flags + local raw_flags + + log="$( mktemp "/tmp/pecl-configure-${name}-XXXX.log" )" + + # Let's ease installation of some extensions: + case "${name}" in + "oci8") + flags=("--with-oci8=instantclient,${ORACLE_HOME}") + ;; + + "scoutapm") + flags=("--enable-scoutapm") + ;; + + "yaml") + flags=("--with-yaml=${BUILD_DIR}/.apt/usr") + ;; + + *) + configure_args_varname="PHP_PECL_EXTENSION_CONFIGURE_ARGS_${name}" + configure_args="$( printenv "${configure_args_varname}" )" + raw_flags="${configure_args//\$BUILD_DIR/${build_dir}}" + + # Transform raw_flags into an array: + readarray -d " " -t flags <<<"${raw_flags} " + unset 'flags[-1]' + ;; + esac + + ./configure --with-php-config=/app/vendor/php/bin/php-config "${flags[@]}" >"${log}" 2>&1 + rc="${?}" + + echo -n "${log}" + + return "${rc}" +} + + +function php::pecl::make_extension() { + local rc=1 + + local name="${1}" + + local log + + log="$( mktemp "/tmp/pecl-make-${name}-XXXX.log" )" + + make -j 2 >"${log}" 2>&1 + rc="${?}" + + echo -n "${log}" + + return "${rc}" +} + + +function php::pecl::compile_extension() { + local rc=0 + + local ext_dir="${1}" + local build_dir="${2}" + local name="${3}" + + pushd "${ext_dir}" >/dev/null \ + || { echo "Unable to enter ${ext_dir}." >&2; return 1; } + + if ! log="$( php::pecl::package_extension "${name}" )"; then + rc="${?}" + cat "${log}" fi + + if [ "${rc}" -eq 0 ]; then + if ! log="$( php::pecl::configure_extension "${name}" "${build_dir}" )"; then + rc="${?}" + cat "${log}" + fi + fi + + if [ "${rc}" -eq 0 ]; then + if ! log="$( php::pecl::make_extension "${name}" )"; then + rc="${?}" + cat "${log}" + fi + fi + + popd >/dev/null || return 1 + + return "${rc}" } -function install_pecl_error() { + +function php::pecl::install_extension() { local extension_name="${1}" - local action="${2}" - local log_file="${3}" - - echo - tail -n 30 "${log_file}" | indent - echo - # This sleep prevents from having the following lines mixed up with the output - # of the above tail. Mystery of shellscripting. - sleep 0.1 - warn "Fail to ${action} of PHP PECL extension: ${extension_name}" - echo "Read above logs to understand the source of the issue" | indent - echo - exit 1 + local version="${2}" + local cache_dir="${3}" + + local build_dir + local version_number + local ext_dir + local temp_dir + local extension_temp_dir + local archive + + build_dir="$( pwd )" + version_number="${version}" + ext_dir="/app/vendor/php/lib/php/extensions/no-debug-non-zts-$(php_api_version)" + + + # If version is given as '*', try to retrieve the latest version number: + if [[ "${version}" = '*' ]]; then + if ! version_number="$( php::pecl::get_latest_version "${extension_name}" )"; then + echo "Unable to retrieve '${extension_name}' latest version number. Aborting." >&2 + return 1 + fi + fi + + + # Try to install extension from cache, but never fail: + if php::pecl::install_from_cache "${extension_name}" "${version_number}" "${cache_dir}" "${ext_dir}"; then + echo "Successfully installed '${extension_name}' ${version_number} from cache." + return 0 + fi + + + # The extension is not cached, we have to install it. + echo "Installing PECL extension '${extension_name}' ${version_number}" | indent + + temp_dir="$( mktmpdir "pecl-extension" )" + extension_temp_dir="${temp_dir}/${extension_name}-${version_number}" + + # Download: + if ! archive="$( php::pecl::download_extension "${extension_name}" "${version_number}" "${temp_dir}" )"; then + echo "Unable to download PECL extension '${extension_name}' ${version_number}. Aborting." >&2 + return 1 + fi + + # Extract: + if ! php::pecl::extract_extension "${archive}" "${extension_temp_dir}"; then + echo "Unable to unpack PECL extension '${extension_name}'. Aborting." >&2 + return 1 + fi + + # Compile: + if ! php::pecl::compile_extension "${extension_temp_dir}" "${build_dir}" "${extension_name}"; then + echo "Unable to compile PECL extension '${extension_name}'. Aborting." >&2 + return 1 + fi + + pushd "${extension_temp_dir}" >/dev/null \ + || { echo "Unable to enter ${extension_temp_dir}." >&2; return 1; } + + cp "modules/${extension_name}.so" "${ext_dir}/${extension_name}.so" + cp "modules/${extension_name}.so" "${cache_dir}/${extension_name}-${version_number}.so" + + popd >/dev/null || return 1 + + if ! php::pecl::enable_extension "${extension_name}"; then + echo "Unable to activate PECL extension '${extension_name}' ${version_number}. Aborting." >&2 + return 1 + else + echo "Successfully installed PECL extension '${extension_name}' ${version_number}." + return 0 + fi } diff --git a/lib/scout b/lib/scout deleted file mode 100644 index 58a5ebb7..00000000 --- a/lib/scout +++ /dev/null @@ -1,22 +0,0 @@ -function install_scout() { - status "ScoutAPM usage detected, installing PHP extension" - - local ext_dir=/app/vendor/php/lib/php/extensions/no-debug-non-zts-$(php_api_version) - local version="${1}" - local cwd=$(pwd) - local temp_dir=$(mktmpdir "scout") - - cd "${temp_dir}" - - curl --location "https://pecl.php.net/get/scoutapm-${version}.tgz" | tar xzv - - cd scoutapm-${version} - /app/vendor/php/bin/phpize - ./configure --with-php-config=/app/vendor/php/bin/php-config --enable-scoutapm - - make - cp modules/scoutapm.so "${ext_dir}/scoutapm.so" - echo "zend_extension=scoutapm.so" > "/app/vendor/php/etc/conf.d/scoutapm.ini" - - cd "${cwd}" -}