From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 7AFFD158170 for ; Wed, 17 Jul 2024 12:06:30 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 7132C2BC0C8; Wed, 17 Jul 2024 12:06:00 +0000 (UTC) Received: from mail-lj1-x229.google.com (mail-lj1-x229.google.com [IPv6:2a00:1450:4864:20::229]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id E7E082BC096 for ; Wed, 17 Jul 2024 12:05:59 +0000 (UTC) Received: by mail-lj1-x229.google.com with SMTP id 38308e7fff4ca-2eee1384e85so48413951fa.2 for ; Wed, 17 Jul 2024 05:05:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1721217958; x=1721822758; darn=lists.gentoo.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9p3NoMi0Yx1HK5MRxpsmzbkrCWeBWDpllvsdcu2KJ2E=; b=dCnx6ATXN+Ipm4qrCj8QYeMXKfPjeVxRJ/+k80jARm9plGwMnPsJ1AIoSpms9uZfQZ 9tISddVes6LXy0d71PnyEs5igo147KkawXBKdbVxY+P2OwTKSB6aPjspjgIe2k5Jttty 5zjqzoPNH4Dbbt3mhy4TNmJGLTgMCOcFmgG1CYAL93tRdK5zaJxLr7yUkoZeFS+5mKCe CmxYVDlebBlvIZG942B3SFmFdqsf7KB6/hsnCppx/L1VUPoZ2w+Ohrx19I2iIVJopB+v wRaBlsKdsXNUaVQsTAJZHMWOjDBpJUZrMywfSTo3V1y8uzofCq6ekm0v5SkS7rtCXozZ i70A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721217958; x=1721822758; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9p3NoMi0Yx1HK5MRxpsmzbkrCWeBWDpllvsdcu2KJ2E=; b=BNgVXBEuy3oxKaqAcZPPkZWBY+NK/2JhqbRQo6rlgN9WUfYoQOV7qeXLf4q+R2M/iL 8dCN+ZKd/2k47P0/K8kfzcNwn/Etef0+xmfNwpM32eh21DFWBB1yYKBWHQjt3Ojhy7vU CqK+2c4Aey9sFDp2CxN1dEmpndKXkY3SJOiw2RJsqjWwgXL8l4bIXKhoQGs3w+JC+OMK aQur+12GAuY0t1wjTK4FbaVreTQwYwxAGDW4KC6yJIIKvHidxNvU8QoPjD9bcXPcKRgi Nz2J91E2DF5sA20LlBXB7B7oehu4StTyuc6o8wvmydPd1kwnBoPmqmrU39jNSp1yUTlE 3vsQ== X-Gm-Message-State: AOJu0YzUha/SYz7RymUm90yhRI9sSqaAImM05bP4+2PdLLFL1MSSFbRc TI4GbQJyx4rNC4rCuOxwSw6DZpLcsj4CGAUvHr/Xjc2ANyQM5kLCd88qQw== X-Google-Smtp-Source: AGHT+IHZi/n+GCpiigGoxortF6I0Tl+3tAJQoSw6MOwLLCHiDU78HVjfSIbRrAo4k7lJXJtPnR1uDQ== X-Received: by 2002:a2e:be90:0:b0:2ee:d8ec:ccd2 with SMTP id 38308e7fff4ca-2eefd14afb7mr17256451fa.33.1721217957246; Wed, 17 Jul 2024 05:05:57 -0700 (PDT) Received: from localhost.localdomain ([62.244.50.57]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2eee1914ad5sm14636941fa.79.2024.07.17.05.05.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 Jul 2024 05:05:56 -0700 (PDT) From: Zurab Kvachadze To: gentoo-dev@lists.gentoo.org Cc: Zurab Kvachadze Subject: [gentoo-dev] [RFC PATCH 01/19] nginx.eclass: Add new eclass for building the NGINX server Date: Wed, 17 Jul 2024 15:05:33 +0300 Message-ID: <20240717120553.31866-2-zurabid2016@gmail.com> X-Mailer: git-send-email 2.44.2 In-Reply-To: <20240717120553.31866-1-zurabid2016@gmail.com> References: <20240717120553.31866-1-zurabid2016@gmail.com> Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-dev@lists.gentoo.org Reply-to: gentoo-dev@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Archives-Salt: 07ee6f88-240d-48e7-a5c4-0d0663842437 X-Archives-Hash: 38f426144d764765a5edccec9ab870ba This adds a generic eclass for building, testing and installing NGINX distributions (F5's NGINX, freenginx, etc). This is a complete revamp of the way NGINX is packaged in Gentoo. The problem =========== NGINX has not been maintained for almost 2 years, since June 5 2022 (commit 9061b2f2318: "*/*: reassign whissi's packages"). In its current state, NGINX has 16 open bugs, with the oldest being reported more than 10 years ago (471106, 496318 and a few more). Moreover, each NGINX ebuild is over 1100 lines of code and 40 kilobytes in size, with enormous amounts of code being copied over with each version bump. Currently, these are some of the most obvious issues. There is another major problem: the www-servers/nginx package bundles 25 third party modules. This inflexible approach has its own issues: * version pinning (of the external modules). * no trivial way to add other external modules (for the end user). The actual code is very old, has inconsistent USE flag choices (http{2,3} being USE flags on their own rather than NGINX_MODULES_HTTP USE_EXPAND flags, the same goes for the ssl USE flag, etc.), outright useless USE flags that do nothing at all (pcre-jit and ktls), outdated dependencies (libpcre instead of libpcre2 by default), mixed shell constructs ('[' somewhere and '[[' elsewhere). The ebuild adds the default include paths to CFLAGS and LDFLAGS for no reason and has warnings about the versions as old as 1.10 (released in January 2017); the ebuild configures NGINX to store its temporary files in /var/lib, instead of /var/tmp and so on... Although this does not intend to cover all the flaws of the current state of NGINX in the Gentoo tree, it is blatant that the quality of the NGINX ebuilds are quite poor and that they are overall particularly messy and clunky. So, I deemed "repackaging" NGINX from the ground up an easier task (than fixing the current NGINX ebuild in-place) and went on with it. The solution ============ This eclass aims to fully cover as much of what is in common between different NGINX versions and distributions as possible, which by itself requires a high degree of flexibility in an eclass. The nginx.eclass does not intend to move the aforementioned complexity to a one place, but rather to *get rid* of it entirely. It achieves this by requiring the inheriting ebuilds to provide the "specification" of their version. The specification is really simple and is comprised of 4 variables: * NGINX_MODULES, that defines available modules, i.e "http_perl", "http_geoip", "http_ssl", "http_v3", "mail_imap", etc. * NGINX_SUBSYSTEMS, that defines individual available NGINX servers: "http", "stream" and "mail". * NGINX_TESTS_RV, that defines a partcular revision of NGINX tests. * NGINX_UPDATE_STREAM, that corresponds to the NGINX version type as defined upstream. Currently, it is either "mainline", "stable" or "live" for the Mercurial version. SLOT is derived from this variable. And 1 optional variable: * NGINX_MISC_FILES, that specifies files in FILESDIR, e.g. NGINX main configuration file, NGINX systemd service file, etc. They are installed into specific locations based on their file extension. The nginx.eclass takes care of all the other aspects. This eclass: 1. Sets the default value for DESCRITPION, HOMEPAGE, LICENSE, SRC_URI. SLOT is set to ${NGINX_UPDATE_STREAM}/${PV}. 2. Populates IUSE, based on the NGINX_MODULES and NGINX_SUBSYSTEMS variables. 3. Fills BDEPEND, DEPEND and RDEPEND with general NGINX dependencies. 4. Sets blocks on all possible update streams (that are expressed as SLOT) apart from the current one, in order to disallow installing multiple NGINX versions at once. 5. Sets REQUIRED_USE for inter-module dependencies, unless OVERRIDE_NGINX_MOD_REQUIRED_USE is set. 6. Sets BDEPEND, DEPEND and RDEPEND for external module dependencies, unless OVERRIDE_NGINX_MOD_DEPEND is set. 7. Sets BDEPEND for module test dependencies, unless OVERRIDE_NGINX_MOD_TEST_DEPEND is set. (points 5-7: the nginx.eclass comes with a default list for such dependencies; the REQUIRED_USE and *DEPEND variables are only set for the modules that are present in NGINX_MODULES). 8. Unpacks the sources or clones the Mercurial repository. 9. Configures NGINX, obviously. 10. Compiles NGINX. 11. Tests the compiled binary. The test dependencies have also been brought in line with what tests actually depend on. 12. Installs NGINX, complying with the FHS. The files specified in NGINX_MISC_FILES are installed in their respective directories. If "modules" use flag is enabled, indicating dynamic modules support, NGINX build system is installed into /usr/src/nginx and NGINX headers are installed into /usr/include/nginx. The nginx.eclass also installs Portage set @nginx-modules-rebuild. It groups all the NGINX dynamic modules and is mainly of use for those who install the "live" version. A considerable part of the eclass parses the ebuild variables, the actual phase function code constitues roughly 240 LoC (out of 790 total). Every part of the eclass is thoroughly annotated and documented. The nginx.eclass sets up the infrastructure for resolving the following bugs: * 886537 - "drop support for obsolete dev-libs/libpcre": _ngx_set_mod_depend() makes the http_rewrite module depend only on dev-libs/libpcre2. * 667102 - "...installing to one or more unexpected paths: /run": already fixed? In any case, this eclass makes sure NGINX does not install anything into /run in nginx_src_install(). * 578658 - "silently ignoring USE=http": nginx.eclass introduces the "http" USE flag, which is a master switch for the whole http subsystem. * 573710 - "Add support for external 3rd party modules": nginx.eclass acts as a foundation for such support. The actual support for building dynamic modules will be in a separate eclass - nginx-module.eclass. * 735020 - "missing a USE flag for building --with-stream only": nginx.eclass adds the "stream" flag to IUSE, allowing the subsystem to be enabled without requiring to alter the NGINX_MODULES_STREAM variable. * 700866 - "use default log names": this eclass uses the default {access,error}.log filenames, instead of {access,error}_log. * 925098 - "www-servers/freenginx - new package": with this eclass, adding freenginx to the Gentoo tree is as simple as setting the aforementioned NGINX_* variables, inheriting nginx.eclass and setting the proper HOMEPAGE, DESCRITPION and SRC_URI. It is crucial to also add block on www-servers/nginx, so that the two packages are not installed simultaneously. Nonetheless, the procedure desribed above is not comprehensive; freenginx will not be regarded by the package manager as a drop-in replacement of F5's NGINX for external modules. To achieve this, a separate virtual/nginx ebuild must be created. Bug: https://bugs.gentoo.org/886537 Bug: https://bugs.gentoo.org/667102 Bug: https://bugs.gentoo.org/578658 Bug: https://bugs.gentoo.org/573710 Bug: https://bugs.gentoo.org/735020 Bug: https://bugs.gentoo.org/700866 Bug: https://bugs.gentoo.org/925098 Signed-off-by: Zurab Kvachadze --- eclass/nginx.eclass | 774 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 774 insertions(+) create mode 100644 eclass/nginx.eclass diff --git a/eclass/nginx.eclass b/eclass/nginx.eclass new file mode 100644 index 000000000000..527171a7bc59 --- /dev/null +++ b/eclass/nginx.eclass @@ -0,0 +1,774 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: nginx.eclass +# @MAINTAINER: +# Zurab Kvachadze +# @AUTHOR: +# Zurab Kvachadze +# @SUPPORTED_EAPIS: 8 +# @PROVIDES: toolchain-funcs multiprocessing systemd perl-functions +# @BLURB: Provides a common set of functions for building the NGINX server +# @DESCRIPTION: +# This eclass automates building, testing and installation of the NGINX server. +# Essentially, apart from the advanced usage, the ebuild must only define 4 +# variables prior to inheriting the eclass, everything else is handled by the +# nginx.eclass. +# Refer to the individual variable descriptions for documentation. The required +# variables are: +# - NGINX_SUBSYSTEMS +# - NGINX_MODULES +# - NGINX_UPDATE_STREAM +# - NGINX_TESTS_RV +# And 1 optional variable (see description): +# - NGINX_MISC_FILES + +case ${EAPI} in + 8) ;; + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;; +esac + +if [[ -z ${_NGINX_ECLASS} ]]; then +_NGINX_ECLASS=1 + +inherit toolchain-funcs multiprocessing systemd perl-functions + +#----> ebuild-defined variables <----- + +# @ECLASS_VARIABLE: NGINX_SUBSYSTEMS +# @PRE_INHERIT +# @REQUIRED +# @DESCRIPTION: +# An array of individual NGINX "servers" or, as they are called in this eclass, +# subsystems. An optional '+' prefix represents a default-enabled state. +# The variable must be an exact representation of the upstream policy, i.e. the +# subsystems that are enabled-by-default upstream must be prefixed with a '+' in +# this array and the subsystems that are disabled-by-default must not be +# prefixed with a '+'. Not following this rule will break NGINX build system. As +# of the time of writing, there are 3 subsystems: "http", "stream", and "mail". +# The naming is the exact representation of ./configure's '--with' and +# '--without' options with the mentioned parts stripped and '+' appended where +# relevant: '--without-http' -> '+http', '--with-stream' -> 'stream', etc. +# +# Example: +# @CODE +# NGINX_SUBSYSTEMS=( +http stream mail ) +# @CODE +[[ ${#NGINX_SUBSYSTEMS[@]} -eq 0 ]] && + die "The required NGINX_SUBSYSTEMS variable is unset or empty" + +# @ECLASS_VARIABLE: _NGX_SUBSYSTEMS +# @INTERNAL +# @DESCRIPTION: +# Internal, read-only copy of NGINX_SUBSYSTEMS, used in various places in the +# eclass. +readonly _NGX_SUBSYSTEMS=( "${NGINX_SUBSYSTEMS[@]}" ) + +# @ECLASS_VARIABLE: NGINX_MODULES +# @PRE_INHERIT +# @REQUIRED +# @DESCRIPTION: +# An array of bundled NGINX modules names with optional '+' prefix +# representing a default-enabled state. +# The variable must be an exact representation of the upstream policy, i.e. the +# modules that are enabled-by-default upstream must be prefixed with a '+' in +# this array and the modules that are disabled-by-default must not be prefixed +# with a '+'. Not following this rule will break NGINX build system. +# The naming scheme is exactly the same as used by the ./configure script with +# '--with(out)' and '_module' parts stripped and the '+' prefix applied where +# necessary: '--with-http_v2_module' -> 'http_v2', +# '--without-http_autoindex_module' -> '+http_autoindex', +# '--without-stream_limit_conn_module' -> '+stream_limit_conn', etc. +# +# Example: +# @CODE +# NGINX_MODULES=( +# +http_rewrite http_ssl +http_gzip +# +stream_access +# +mail_imap +# http_{geoip,perl} +# ) +# @CODE +[[ ${#NGINX_MODULES[@]} -eq 0 ]] && + die "The required NGINX_MODULES variable is unset or empty" + +# @ECLASS_VARIABLE: _NGX_MODULES +# @INTERNAL +# @DESCRIPTION: +# Internal, read-only copy of NGINX_MODULES, used in various places in the +# nginx.eclass. +readonly _NGX_MODULES=( "${NGINX_MODULES[@]}" ) + +# @ECLASS_VARIABLE: NGINX_UPDATE_STREAM +# @PRE_INHERIT +# @REQUIRED +# @DESCRIPTION: +# This variable must contain the update stream for NGINX. The list of all +# possible update streams is set by the NGX_UPDATE_STREAMS_LIST variable. An +# ebuild must not attempt to set SLOT manually. The eclass will automatically +# set SLOT and add blocks on other update streams into RDEPEND variable, based +# on this variable. +# NGINX_UPDATE_STREAM might be set to a special value: 'live'. Doing this makes +# the eclass fetch the live (latest) version of NGINX from its Mercurial +# repository. +# This behaviour can be further configured by setting the following variables +# (refer to each variable description for documentation): +# - NGINX_HG_URI +# - NGINX_HG_TESTS_URI +# +# Example: +# @CODE +# NGINX_UPDATE_STREAM=mainline +# @CODE + +# @ECLASS_VARIABLE: NGX_UPDATE_STREAMS_LIST +# @DESCRIPTION: +# Read-only array that contains all the possible NGINX update +# streams. +readonly NGX_UPDATE_STREAMS_LIST=( stable mainline live ) + +[[ -z ${NGINX_UPDATE_STREAM} ]] && + die "The required NGINX_UPDATE_STREAM variable is unset or empty" +has "${NGINX_UPDATE_STREAM}" "${NGX_UPDATE_STREAMS_LIST[@]}" || + die "Unknown update stream set in the NGINX_UPDATE_STREAM variable" + +[[ ${NGINX_UPDATE_STREAM} == live ]] && inherit mercurial + +# @ECLASS_VARIABLE: NGINX_TESTS_RV +# @PRE_INHERIT +# @REQUIRED +# @DESCRIPTION: +# This variable must contain a valid revision of nginx-tests[1] repository. The +# tests for NGINX are unversioned, therefore their snapshot is obtained from the +# specified revision. +# Only in case the NGINX_UPDATE_STREAM variable is set to 'live', this variable +# might alternatively be set exactly to 'live' in order to fetch the latest +# revision of the nginx-tests[1] repository. +# [1]: https://hg.nginx.org/nginx-tests/ +# +# Example: +# @CODE +# NGINX_TESTS_REVISION=6e83940ac1df +# @CODE +[[ -z ${NGINX_TESTS_RV} ]] && + die "The required NGINX_TESTS_RV variable is unset or empty" +[[ ${NGINX_TESTS_RV} == live && ${NGINX_UPDATE_STREAM} != live ]] && + die "Live tests can not be used with a non-live version of NGINX" + +# @ECLASS_VARIABLE: NGINX_HG_URI +# @DESCRIPTION: +# May be set to an alternative URI of NGINX Mercurial repository for the live +# version to be fetched from. Defaults to "https://hg.nginx.org/nginx". +: "${NGINX_HG_URI=https://hg.nginx.org/nginx}" + +# @ECLASS_VARIABLE: NGINX_HG_TESTS_URI +# @DESCRIPTION: +# May be set to an alternative URI of NGINX tests Mercurial repository for the +# live version to be fetched from. Defaults to "https://hg.nginx.org/nginx-tests". +: "${NGINX_HG_TESTS_URI=https://hg.nginx.org/nginx-tests}" + +# @ECLASS_VARIABLE: NGINX_MISC_FILES +# @DEFAULT_UNSET +# @DESCRIPTION: +# This array holds the filenames of files in FILESDIR. The files that are +# specified in this array are installed to various locations, based on +# their file extension. The "file extension - path" mappings are as follows: +# '.conf' -> '/etc/nginx' +# '.service' -> systemd unit directory +# '.initd' -> '/etc/init.d' +# '.confd' -> '/etc/conf.d' +# '.logrotate' -> '/etc/logrotate.d' +# This variable exists to avoid (1) hardcoding specific versions of the files +# that may change due to revisions (the revisions happen rather frequently in +# case of NGINX), (2) repeating the code which installs the files in every +# ebuild, and (3) requiring these miscellaneous files to exist at all. +# +# Example: +# @CODE +# NGINX_MISC_FILES=( +# nginx-r5.initd nginx-r4.conf nginx-r1.confd nginx-{r2.logrotate,r2.service} +# ) +# @CODE + +# @ECLASS_VARIABLE: OVERRIDE_NGINX_MOD_REQUIRED_USE +# @DEFAULT_UNSET +# @PRE_INHERIT +# @DESCRIPTION: +# Set this to a non-empty value prior to inheriting the eclass to NOT +# automatically fill the REQUIRED_USE variable with inter-module dependencies. +# For details, see _ngx_set_mod_required_use() function description below. + +# @ECLASS_VARIABLE: OVERRIDE_NGINX_MOD_DEPEND +# @DEFAULT_UNSET +# @PRE_INHERIT +# @DESCRIPTION: +# Set this to a non-empty value prior to inheriting the eclass to NOT +# automatically fill the BDEPEND, DEPEND, and RDEPEND variables with module +# dependencies. +# For details, see _ngx_set_mod_depend() function description below. + +# @ECLASS_VARIABLE: OVERRIDE_NGINX_MOD_TEST_DEPEND +# @DEFAULT_UNSET +# @PRE_INHERIT +# @DESCRIPTION: +# Set this to a non-empty value prior to inheriting the eclass to NOT +# automatically fill the BDEPEND variable with module test dependencies. +# For details, see _ngx_set_mod_test_depend() function description below. + +#----> ebuild setup <---- + +# NGINX does not guarantee ABI stability (required by dynamic modules), SLOT is +# set to reflect this. +SLOT="${NGINX_UPDATE_STREAM}/${PV}" +: "${DESCRIPTION=Robust, small and high performance HTTP and reverse proxy server}" +: "${HOMEPAGE=https://nginx.org}" +if [[ -z ${SRC_URI} ]]; then + if [[ ${NGINX_UPDATE_STREAM} != live ]]; then + SRC_URI="https://nginx.org/download/${P}.tar.gz" + fi + if [[ ${NGINX_TESTS_RV} != live ]]; then + SRC_URI+=" + test? ( + https://hg.nginx.org/nginx-tests/archive/${NGINX_TESTS_RV}.tar.gz -> + nginx-tests-${NGINX_TESTS_RV}.tar.gz + ) + " + fi +fi +: "${LICENSE=BSD-2}" + +# @ECLASS_VARIABLE: NGX_TESTS_S +# @OUTPUT_VARIABLE +# @DESCRIPTION: +# Variable set to the work directory of the NGINX tests. +NGX_TESTS_S="${WORKDIR}/nginx-tests-${NGINX_TESTS_RV}" + +#----> Generic helper functions <----- + +# @FUNCTION: econf_ngx +# @USAGE: [...] +# @DESCRIPTION: +# Call ./configure, passing the supplied arguments. +# The NGINX build system consists of many helper scripts, which are executed +# relative to the working directory. Therefore, the function only supports +# executing the ./configure script from the current working directory. This +# function also checks whether the script is executable. If any of the above +# conditions are not satisfied, the function aborts the build process with +# 'die'. It also fails if the script itself exits with a non-zero exit code, +# unless the function is called with 'nonfatal'. +# If running ./configure is required, this is the way it should be done. +econf_ngx() { + debug-print-function "${FUNCNAME[0]}" "$@" + [[ -x ./configure ]] || + die "./configure is not present in the current working directory or is not executable" + echo "./configure ${*@Q}" >&2 + ./configure "$@" + # For some reason, NGINX ./configure returns 1 if it is used with the + # '--help' argument. + if [[ $? -ne 0 && $1 != --help ]]; then + die -n "./configure ${*@Q} failed" + fi +} + +#----> USE logic <---- + +# @FUNCTION: _ngx_populate_iuse +# @INTERNAL +# @DESCRIPTION: +# Populates IUSE with parsed entries from NGINX_SUBSYSTEMS and NGINX_MODULES. +_ngx_populate_iuse() { + local mod state + IUSE+=" ${_NGX_SUBSYSTEMS[*]}" + for mod in "${_NGX_MODULES[@]}"; do + if [[ "${mod:0:1}" == + || ${mod} == *_ssl ]]; then + state=+ + else + state='' + fi + IUSE+=" ${state}nginx_modules_${mod#+}" + done +} + +IUSE="aio debug libatomic +modules selinux test" +REQUIRED_USE="|| ( ${_NGX_SUBSYSTEMS[*]#+} )" +RESTRICT="!test? ( test )" + +_ngx_populate_iuse + +unset -f _ngx_populate_iuse + +#----> *DEPEND stuff <---- + +BDEPEND=" + test? ( + dev-lang/perl + virtual/perl-IO-Compress + virtual/perl-Test-Simple + virtual/perl-Test-Harness + ) +" + +DEPEND=" + acct-group/nginx + acct-user/nginx + virtual/libcrypt + libatomic? ( dev-libs/libatomic_ops ) +" + +RDEPEND=" + ${DEPEND} + app-misc/mime-types[nginx] + selinux? ( sec-policy/selinux-nginx ) +" + + +# @FUNCTION: _ngx_set_blocks +# @INTERNAL +# @USAGE: [...] +# @DESCRIPTION: +# Set blocks on all the supplied update streams apart from the chosen one. +_ngx_set_blocks() { + debug-print-function "${FUNCNAME[0]}" "$@" + [[ $# -ge 2 ]] || die "${FUNCNAME[0]} must receive at least two arguments" + local chosen candidate + chosen="$1" + shift + for candidate; do + [[ ${candidate} != "${chosen}" ]] && + RDEPEND+=" !${CATEGORY}/${PN}:${candidate}" + done +} + +# Null at the end makes the function also block the legacy unslotted NGINX versions. +_ngx_set_blocks "${NGINX_UPDATE_STREAM}" "${NGX_UPDATE_STREAMS_LIST[@]}" 0 + + +# @FUNCTION: _ngx_set_mod_required_use +# @INTERNAL +# @DESCRIPTION: +# Sets the REQUIRED_USE variable for inter-modules dependencies. The subscript +# specifies the target module and the value is a comma separated list of the +# modules the subscript depends on. +# This function comes with a predefined associative array of dependencies (that +# should be updated, in case they change, get added/removed), for each ebuild +# to not redundantly specify these. +# The function adds dependencies only if the corresponding module is specified +# in the NGINX_MODULES variable, defined by the ebuild. Therefore, it is safe +# to add new modules to the default list, since the respective dependencies +# will not be set for the versions that do not have the modules in question. +# This function is always executed, unless OVERRIDE_NGINX_MOD_REQUIRED_USE is +# set to a non-empty value (see the variable description). +_ngx_set_mod_required_use() { + local -A _NGX_DEP_TABLE=( + [http_v3]=http_ssl + [http_grpc]=http_v2 + ) + + local mod dep_list dep result + # Iterate over all the indexes. + for mod in "${!_NGX_DEP_TABLE[@]}"; do + if has "${mod}" "${_NGX_MODULES[@]}"; then + result='' + # Feed the comma-delimited dependencies into the dep_list array. + IFS=, read -ra dep_list <<< "${_NGX_DEP_TABLE[${mod}]}" + for dep in "${dep_list[@]}"; do + has "${dep}" "${_NGX_MODULES[@]}" && + result+=" nginx_modules_${dep}" + done + [[ -n ${result} ]] && + REQUIRED_USE+=" + nginx_modules_${mod}? ( ${result} ) + " + fi + done +} + +# @FUNCTION: _ngx_set_mod_depend +# @INTERNAL +# @DESCRIPTION: +# Fills the {,B,R}DEPEND variables with external module dependencies. +# This function comes with a predefined associative array of dependencies (that +# should be updated, in case they change, get added/removed), for each ebuild to +# not redundantly specify these. +# The function adds dependencies only if the corresponding module is specified +# in the NGINX_MODULES variable, defined by the ebuild. Therefore, it is safe to +# add new modules to the default list, since they will not propagate to the +# versions that do not have the modules in question. +# This function is always executed, unless OVERRIDE_NGINX_MOD_DEPEND is set to a +# non-empty value (see the variable description). +_ngx_set_mod_depend() { + # The highest common denominator of module dependencies. + local -A CDEPEND=( + [http_image_filter]="media-libs/gd:=" + [http_geoip]="dev-libs/geoip" + [http_gunzip]="sys-libs/zlib:=" + [http_gzip]="sys-libs/zlib:=" + [http_rewrite]="dev-libs/libpcre2:=" + [http_ssl]="dev-libs/openssl:=" + # http_v3 requires NGINX QUIC compatibility layer that uses + # SSL_CTX_add_custom_ext OpenSSL interface, which was introduced in + # OpenSSL 1.1.1. + [http_v3]=">=dev-libs/openssl-1.1.1:=" + [http_xslt]=" + dev-libs/libxml2:= + dev-libs/libxslt + " + [mail_ssl]="dev-libs/openssl:=" + [stream_geoip]="dev-libs/geoip" + [stream_ssl]="dev-libs/openssl:=" + ) + local CDEPEND_DEF + # Bash does not have an easy way to copy an associative array, so its value + # is obtained using the 'declare' builtin. + CDEPEND_DEF="$(declare -p CDEPEND)" + + local -A _NGX_MOD_BDEPEND=( + [http_perl]="dev-lang/perl" + ) + local -A _NGX_MOD_DEPEND="${CDEPEND_DEF#*=}" + _NGX_MOD_DEPEND+=( + [http_perl]="dev-lang/perl" + ) + local -A _NGX_MOD_RDEPEND="${CDEPEND_DEF#*=}" + _NGX_MOD_RDEPEND+=( + [http_perl]="dev-lang/perl:=" + ) + + local mod dep_type dep_table + # Make dep_table a reference to one of the _NGX_MOD_* variables defined + # above, then make dep_type itself a reference to the dependency variable. + for dep_type in {,B,R}DEPEND; do + declare -n dep_table="_NGX_MOD_${dep_type}" + declare -n dep_type + # Iterate over all the indexes of the referenced variable. + for mod in "${!dep_table[@]}"; do + if has "${mod}" "${_NGX_MODULES[@]}"; then + dep_type+=" nginx_modules_${mod}? ( ${dep_table[${mod}]} )" + fi + done + # Reset the 'name reference' attribute. + declare +n dep_table dep_type + done +} + +# @FUNCTION: _ngx_set_mod_test_depend +# @INTERNAL +# @DESCRIPTION: +# Fills the BDEPEND variable with module test dependencies. +# This function comes with a predefined associative array of dependencies (that +# should be updated, in case they change, get added/removed), for each ebuild to +# not redundantly specify these. +# The function adds dependencies only if the corresponding module is specified +# in the NGINX_MODULES variable, defined by the ebuild. Therefore, it is safe to +# add new modules to the default list, since they will not propagate to the +# versions that do not have the modules in question. +# This function is always executed, unless OVERRIDE_NGINX_MOD_TEST_DEPEND is set +# to a non-empty value (see the variable description). +_ngx_set_mod_test_depend() { + # A few notes: + # - http_scgi needs SCGI Perl module, which is not packaged by Gentoo, + # - http_proxy needs Protocol::Websocket, not packaged by Gentoo. + local -A _NGX_MOD_TEST_DEP=( + [http_fastcgi]="dev-perl/FCGI" + [http_image_filter]="dev-perl/GD" + [http_memcached]=" + dev-perl/Cache-Memcached + dev-perl/Cache-Memcached-Fast + net-misc/memcached + " + [http_ssl]=" + dev-perl/IO-Socket-SSL + dev-perl/Net-SSLeay + " + [http_v3]="dev-perl/CryptX" + [mail_ssl]="dev-perl/IO-Socket-SSL" + [stream_ssl]="dev-perl/IO-Socket-SSL" + ) + local mod result= + for mod in "${!_NGX_MOD_TEST_DEP[@]}"; do + if has "${mod}" "${_NGX_MODULES[@]}"; then + result+=" nginx_modules_${mod}? ( ${_NGX_MOD_TEST_DEP[${mod}]} )" + fi + done + [[ -n ${result} ]] && + BDEPEND+=" test? ( ${result} )" +} + +[[ -z ${OVERRIDE_NGINX_MOD_REQUIRED_USE} ]] && + _ngx_set_mod_required_use + +[[ -z ${OVERRIDE_NGINX_MOD_DEPEND} ]] && + _ngx_set_mod_depend + +[[ -z ${OVERRIDE_NGINX_MOD_TEST_DEPEND} ]] && + _ngx_set_mod_test_depend + +unset -f _ngx_set_blocks _ngx_set_mod_required_use _ngx_set_mod_depend \ + _ngx_set_mod_test_depend + +#----> Phase functions <---- + +# @FUNCTION: nginx_src_unpack +# @DESCRIPTION: +# Unpacks the NGINX sources. For the live version of NGINX, fetches the tip +# of the Mercurial repository. +nginx_src_unpack() { + if [[ ${NGINX_UPDATE_STREAM} == live ]]; then + mercurial_fetch "${NGINX_HG_URI}" + # In Mercurial repo, ./configure script is located in auto/ folder. + mv "${S}/auto/configure" "${S}/configure" || die "mv failed" + # Non-live tests for any update stream are taken care of in SRC_URI. + if use test && [[ ${NGINX_TESTS_RV} == live ]]; then + local EHG_CHECKOUT_DIR="${NGX_TESTS_S}" + mercurial_fetch "${NGINX_HG_TESTS_URI}" + fi + fi + default +} + +# @FUNCTION: nginx_src_configure +# @DESCRIPTION: +# Configures NGINX. It initialises the default set of configure flags, coupled +# with the USE-conditional ones. The function also automatically disables and +# enables NGINX modules and subsystems set in NGINX_MODULES and NGINX_SUBSYSTEMS +# respectively. +# Custom flags can be supplied via the 'myconf' array, taking precedence over +# the eclass flags. +nginx_src_configure() { + debug-print-function "${FUNCNAME[0]}" "$@" + local nginx_flags + nginx_flags=( + --with-cc="$(tc-getCC)" + --with-cpp="$(tc-getCPP)" + --with-ld-opt="${LDFLAGS}" + --builddir=build + # NGINX loads modules relative to the prefix, not modules-path + --prefix="${EPREFIX}/usr/$(get_libdir)/nginx" + --sbin-path="${EPREFIX}/usr/sbin/nginx" + --modules-path="${EPREFIX}/usr/$(get_libdir)/nginx/modules" + --conf-path="${EPREFIX}/etc/nginx/nginx.conf" + --error-log-path="${EPREFIX}/var/log/nginx/error.log" + --http-log-path="${EPREFIX}/var/log/nginx/access.log" + --pid-path="${EPREFIX}/run/nginx.pid" + --lock-path="${EPREFIX}/run/lock/nginx.lock" + --user=nginx + --group=nginx + --with-threads + ) + + use aio && nginx_flags+=( --with-file-aio ) + use debug && nginx_flags+=( --with-debug ) + use libatomic && nginx_flags+=( --with-libatomic ) + use modules && nginx_flags+=( --with-compat ) + + # Fix paths for various temporary files. + local conf _txt + while read -r conf _txt; do + conf="${conf%%-temp-path*}" + conf="${conf#--http-}" + nginx_flags+=( + "--http-${conf}-temp-path=${EPREFIX}/var/tmp/nginx/${conf//-/_}_temp" + ) + done < <(econf_ngx --help 2>/dev/null | grep -E -- '--http-([A-Za-z]+-?)+-temp-path') + unset conf _txt + + # For each subsystem and module we check if they diverge from their default + # state and, if that is the case, we pass the corresponding flag to the + # ./configure script. + # This is done this way because NGINX build system does not understand + # arguments that set options to their default state, e.g. ./configure does + # not recognise arguments like '--with-http_rewrite_module', only + # '--without-http_rewrite_module', as http_rewrite module is enabled by + # default. + local subsys mod def_state cur_state + for subsys in "${_NGX_SUBSYSTEMS[@]}"; do + use "${subsys#+}"; cur_state=$? + [[ ${subsys:0:1} == + ]]; def_state=$? + if [[ cur_state -ne def_state ]]; then + nginx_flags+=( "$(use_with "${subsys#+}")" ) + fi + done + for mod in "${_NGX_MODULES[@]}"; do + use "nginx_modules_${mod#+}"; cur_state=$? + [[ ${mod:0:1} == + ]]; def_state=$? + if [[ cur_state -ne def_state ]]; then + nginx_flags+=( "$(use_with "nginx_modules_${mod#+}" "${mod#+}_module")" ) + fi + done + unset subsys mod def_state cur_state + + # Handle arguments containing quoted whitespace. + eval "local -a EXTRA_ECONF=( ${EXTRA_ECONF} )" + + # You never know when bug #286772 may get you. + LC_ALL=C LANG=C econf_ngx \ + "${nginx_flags[@]}" \ + "${myconf[@]}" \ + "${EXTRA_ECONF[@]}" + + sed -E -i \ + -e 's|\$\(LINK\)|$(LINK) $(CFLAGS)|' \ + -e '/^\s*LIB= \\$/d' \ + -e '/^\s*INSTALLSITEMAN3DIR= \\$/d' \ + build/Makefile || die "sed failed" +} + +# @FUNCTION: nginx_src_compile +# @DESCRIPTION: +# Compiles NGINX, setting the correct installation directories for the +# Perl-related files. +nginx_src_compile() { + PERL_MM_OPT='INSTALLDIRS=vendor' emake +} + +# @FUNCTION: nginx_src_test +# @DESCRIPTION: +# Performs tests on the compiled NGINX binary, using Perl's prove. +nginx_src_test() { + pushd "${NGX_TESTS_S}" >/dev/null || die "pushd failed" + echo "prove -j $(makeopts_jobs) ." >&2 + TEST_NGINX_BINARY="${S}/build/nginx" prove -j "$(makeopts_jobs)" . + popd >/dev/null || die "popd failed" +} + +# @FUNCTION: nginx_src_install +# @DESCRIPTION: +# Installs NGINX, including miscellaneous directories under '/var' and +# documentation. Vimfiles from 'contrib/vim' are also installed by this +# function. All the files specified in the NGINX_MISC_FILES array are installed +# in their respective directories. +# If 'modules' USE flag is enabled, the build system (the './configure' script +# and the scripts in the 'auto/' directory) is installed into '/usr/src/nginx' +# and NGINX headers into '/usr/include/nginx'. +nginx_src_install() { + debug-print-function "${FUNCNAME[0]}" "$@" + emake DESTDIR="${ED}" install + keepdir "/usr/$(get_libdir)/nginx/modules" + + keepdir /var/log/nginx + # Set the proper permissions on /var/log/nginx to mitigate CVE-2016-1247 + # (bug #605008). + fperms 0750 /var/log/nginx + fowners root:nginx /var/log/nginx + # NGINX desperately wants to *install* its pidfile (and some web pages). + # Unfortunately, we can not let it do this... + rm -r "${ED}/run" "${ED}/usr/$(get_libdir)/nginx/html" || die "rm failed" + # The default directory for serving web content. + keepdir /var/www + + # Clean /etc/nginx from unneeded files and move the directory to + # /usr/share/nginx. + pushd "${ED}/etc/nginx" >/dev/null || die "pushd failed" + # mime-types* are provided by app-misc/mime-types[nginx], .default config + # files are redundant due to CONFIG_PROTECT and fastcgi.conf is a copy of + # fastcgi_params. As for nginx.conf, we ship our own config file. + rm -- *.default mime.types fastcgi.conf nginx.conf || die "rm failed" + popd >/dev/null || die "Returning to the previous directory failed" + + dodir /usr/share + mv "${ED}/etc/nginx" "${ED}/usr/share/nginx" || die "mv failed" + + insinto /usr/share/nginx + if [[ ${NGINX_UPDATE_STREAM} != live ]]; then + dodoc CHANGES* LICENSE README + doins html/*.html + else + # The Mercurial version has a slightly different file structure. + dodoc docs/text/{LICENSE,README} + doins docs/html/*.html + fi + doman build/nginx.8 + + # Install miscellaneous files in the proper directories, based on their file + # extension (see the description of the NGINX_MISC_FILES variable). + local mfile + for mfile in "${NGINX_MISC_FILES[@]}"; do + case "${mfile}" in + *.conf) insinto /etc/nginx; newins "${FILESDIR}/${mfile}" nginx.conf ;; + *.service) systemd_newunit "${FILESDIR}/${mfile}" nginx.service ;; + *.initd) exeinto /etc/init.d; newexe "${FILESDIR}/${mfile}" nginx ;; + *.confd) insinto /etc/conf.d; newins "${FILESDIR}/${mfile}" nginx ;; + *.logrotate) insinto /etc/logrotate.d; newins "${FILESDIR}/${mfile}" nginx ;; + *) die "Unknown file in NGINX_MISC_FILES: ${mfile}. Please file a bug" ;; + esac + done + + # Install vimfiles from 'contrib/vim'. + insinto /usr/share/vim/vimfiles + doins -r contrib/vim/* + + if in_iuse nginx_modules_http_perl && use nginx_modules_http_perl; then + perl_delete_module_manpages + perl_delete_localpod + perl_fix_packlist + fi + + # For the rationale of the following, see nginx-module.eclass. + if use modules; then + # Install the headers into /usr/include/nginx. + insinto /usr/include/nginx + doins -r src/* + find "${ED}/usr/include/nginx" -type f -not -name '*.h' -delete || + die "find failed" + find "${ED}/usr/include/nginx" -type d -empty -delete || + die "find failed" + # Install the auto-generated headers with #define's to not handle the + # saving and restoration of configuration flags. This is needed for the + # compilation of dynamic modules, since NGINX does not guarantee API + # stability. + insinto /usr/include/nginx + doins build/ngx_auto_{config,headers}.h + # The directory where third-party modules should save their own headers. + keepdir /usr/include/nginx/modules + + # Copy the build system of NGINX to /usr/src/nginx. + insinto /usr/src/nginx + doins -r auto + + # Disable several checks if the _NGINX_GENTOO_SKIP_PHASES variable is + # set to a non-empty value during the invocation of ./configure script. + # This is done since (1) these scripts do not have any effect on the + # build process of third-party modules and (2) they considerably + # increase configuration time. + sed -E -i \ + 's#^\s*\. auto/(unix|lib/conf|headers|summary)$# \ + [ -z "${_NGINX_GENTOO_SKIP_PHASES}" ] \&\& &#' \ + configure || die "sed failed" + # The last statement in ./configure is [ -z "${_NGINX_GENTOO... ]. If + # _NGINX_GENTOO_SKIP_PHASES is non-empty, it evaluates to false and the + # whole ./configure script exits with non-zero exit status. This is done + # to always return zero upon reaching the end of the script. + echo ':' >> configure + exeinto /usr/src/nginx + doexe configure + + # Install the @nginx-module-rebuild set, which groups all the packages + # that have NGINX in BDEPEND, i.e. third-party modules. + dodir /usr/share/portage/config/sets + cat <<- EOF > "${ED}/usr/share/portage/config/sets/nginx-modules.conf" || die "cat failed" + [nginx-modules-rebuild] + class = portage.sets.dbapi.VariableSet + variable = BDEPEND + includes = ${CATEGORY}/${PN} + EOF + fi +} + +# @FUNCTION: nginx_pkg_postinst +# @DESCRIPTION: +# Shows various warnings and informational messages to a user. +nginx_pkg_postinst() { + if use modules && [[ ${NGINX_UPDATE_STREAM} == live ]]; then + ewarn "The live NGINX package is used with modules enabled." + elog "NGINX does not have a stable API or ABI, therefore it is" + elog "necessary for the exact version used to compile a module" + elog "to match the one used at runtime to load the module." + elog "To be able to use NGINX modules compiled against previous" + elog "version of NGINX, they must be rebuilt." + elog "Run 'emerge @nginx-module-rebuild' to rebuild all NGINX modules." + fi +} + +fi + +EXPORT_FUNCTIONS src_unpack src_configure src_compile src_test src_install pkg_postinst -- 2.44.2