public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: Zurab Kvachadze <zurabid2016@gmail.com>
To: gentoo-dev@lists.gentoo.org
Cc: Zurab Kvachadze <zurabid2016@gmail.com>
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	[thread overview]
Message-ID: <20240717120553.31866-2-zurabid2016@gmail.com> (raw)
In-Reply-To: <20240717120553.31866-1-zurabid2016@gmail.com>

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 <zurabid2016@gmail.com>
---
 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 <zurabid2016@gmail.com>
+# @AUTHOR:
+# Zurab Kvachadze <zurabid2016@gmail.com>
+# @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: [<args>...]
+# @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: <chosen_update_stream> <possible_upd_stream1> [<possible_upd_stream2>...]
+# @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



  reply	other threads:[~2024-07-17 12:06 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-17 12:05 [gentoo-dev] [RFC PATCH 00/19] Rework NGINX packaging in Gentoo by introducing nginx{,-module}.eclass Zurab Kvachadze
2024-07-17 12:05 ` Zurab Kvachadze [this message]
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 02/19] nginx-module.eclass: Add new eclass for building NGINX external modules Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 03/19] www-servers/nginx: add myself as a proxy maintainer; update metadata.xml Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 04/19] www-servers/nginx: add nginx-r5.initd Zurab Kvachadze
2024-07-17 12:41   ` Michael Orlitzky
2024-07-19  9:20     ` Zurab Kvachadze
2024-07-19 10:31       ` Michael Orlitzky
2024-07-19 16:33         ` Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 05/19] www-servers/nginx: add nginx-r1.confd Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 06/19] www-servers/nginx: add nginx-r2.service Zurab Kvachadze
2024-07-20 16:58   ` Alexander Tsoy
2024-07-20 17:15     ` Michael Orlitzky
2024-07-20 17:25       ` Alexander Tsoy
2024-07-20 19:17         ` Alexander Tsoy
2024-07-20 21:07         ` Michael Orlitzky
2024-07-21 21:19           ` Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 07/19] www-servers/nginx: add nginx-r2.logrotate Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 08/19] www-servers/nginx: add nginx-r4.conf Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 09/19] profiles/desc: reword and update nginx_modules_http.desc Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 10/19] profiles/desc: reword and update nginx_modules_mail.desc Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 11/19] profiles/desc: reword and update nginx_modules_stream.desc Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 12/19] profiles/categories: Add www-nginx category for external NGINX modules Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 13/19] www-servers/nginx: revbump 1.26.1-r1 to 1.26.1-r2, use nginx.eclass Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 14/19] www-servers/nginx: revbump 1.27.0-r1 to 1.27.0-r2, " Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 15/19] www-servers/nginx: add 9999 live version, " Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 16/19] www-nginx/ngx_devel_kit: new package, add 0.3.3 Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 17/19] www-nginx/ngx-echo: new package, add 0.63 Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 18/19] www-nginx/ngx-encrypted-session: new package, add 0.09 Zurab Kvachadze
2024-07-17 12:05 ` [gentoo-dev] [RFC PATCH 19/19] www-nginx/ngx-set-misc: new package, add 0.33 Zurab Kvachadze

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240717120553.31866-2-zurabid2016@gmail.com \
    --to=zurabid2016@gmail.com \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox