From 9f93e30eb9b716f7e4adbb71d11a57911872201c Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 2 Apr 2024 22:28:30 +0200 Subject: [PATCH] Do not export A in EAPI 9 Instead of passing A as part of the process environment, we pass it via a file. Since A is usually the greatest contributor to the process environment, removing it from the process environment significantly avoids running into MAX_ARG_STRLEN when spawning a new child process. This means that A is no longer exported in the ebuild and hence unavaiable to child processes. However, A is mostly used as part of the default_src_unpack function and there A does not need to be exported. Thanks to Zac Medico for helpful input on this change. Closes: https://bugs.gentoo.org/721088 Signed-off-by: Florian Schmaus --- bin/ebuild.sh | 7 +++++- lib/portage/const.py | 1 + lib/portage/eapi.py | 10 ++++++++- lib/portage/package/ebuild/doebuild.py | 31 +++++++++++++++++++++++++- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/bin/ebuild.sh b/bin/ebuild.sh index a742397db9..0a55ffc582 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright 1999-2021 Gentoo Authors +# Copyright 1999-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # Prevent aliases from causing portage to act inappropriately. @@ -10,6 +10,11 @@ unalias -a unset BASH_COMPAT declare -F ___in_portage_iuse >/dev/null && export -n -f ___in_portage_iuse +if [[ -v PORTAGE_EBUILD_EXTRA_SOURCE ]]; then + source "${PORTAGE_EBUILD_EXTRA_SOURCE}" || exit 1 + unset PORTAGE_EBUILD_EXTRA_SOURCE +fi + source "${PORTAGE_BIN_PATH}/isolated-functions.sh" || exit 1 # Set up the bash version compatibility level. This does not disable diff --git a/lib/portage/const.py b/lib/portage/const.py index c9a71009a7..d25e3692c6 100644 --- a/lib/portage/const.py +++ b/lib/portage/const.py @@ -181,6 +181,7 @@ "digest", "distcc", "distlocks", + "dont-export-a", "downgrade-backup", "ebuild-locks", "fail-clean", diff --git a/lib/portage/eapi.py b/lib/portage/eapi.py index 86b27bdbc5..f9eafa18c3 100644 --- a/lib/portage/eapi.py +++ b/lib/portage/eapi.py @@ -1,4 +1,4 @@ -# Copyright 2010-2021 Gentoo Authors +# Copyright 2010-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 import collections @@ -48,6 +48,10 @@ def eapi_supports_prefix(eapi: str) -> bool: return _get_eapi_attrs(eapi).prefix +def eapi_exports_A(eapi: str) -> bool: + return _get_eapi_attrs(eapi).exports_A + + def eapi_exports_AA(eapi: str) -> bool: return _get_eapi_attrs(eapi).exports_AA @@ -152,6 +156,7 @@ def eapi_has_sysroot(eapi: str) -> bool: "broot", "dosed_dohard", "empty_groups_always_true", + "exports_A", "exports_AA", "exports_EBUILD_PHASE_FUNC", "exports_ECLASSDIR", @@ -198,6 +203,7 @@ class Eapi: "6", "7", "8", + "9", ) _eapi_val: int = -1 @@ -231,6 +237,7 @@ def _get_eapi_attrs(eapi_str: Optional[str]) -> _eapi_attrs: broot=True, dosed_dohard=False, empty_groups_always_true=False, + exports_A=True, exports_AA=False, exports_EBUILD_PHASE_FUNC=True, exports_ECLASSDIR=False, @@ -270,6 +277,7 @@ def _get_eapi_attrs(eapi_str: Optional[str]) -> _eapi_attrs: broot=eapi >= Eapi("7"), dosed_dohard=eapi <= Eapi("3"), empty_groups_always_true=eapi <= Eapi("6"), + exports_A=eapi <= Eapi("8"), exports_AA=eapi <= Eapi("3"), exports_EBUILD_PHASE_FUNC=eapi >= Eapi("5"), exports_ECLASSDIR=eapi <= Eapi("6"), diff --git a/lib/portage/package/ebuild/doebuild.py b/lib/portage/package/ebuild/doebuild.py index 1d257d52db..208d2dd049 100644 --- a/lib/portage/package/ebuild/doebuild.py +++ b/lib/portage/package/ebuild/doebuild.py @@ -82,6 +82,7 @@ ) from portage.dep.libc import find_libc_deps from portage.eapi import ( + eapi_exports_A, eapi_exports_KV, eapi_exports_merge_type, eapi_exports_replace_vars, @@ -2133,9 +2134,37 @@ def spawn( logname_backup = mysettings.configdict["env"].get("LOGNAME") mysettings.configdict["env"]["LOGNAME"] = logname + eapi = mysettings["EAPI"] + + unexported_env_vars = set() + if "dont-export-a" in mysettings.features or not eapi_exports_A(eapi): + unexported_env_vars.add("A") + + if unexported_env_vars: + orig_env = mysettings.environ() + # Copy since we are potentially removing keys from the dict. + env = orig_env.copy() + + t = env["T"] + if not os.path.isdir(t): + os.makedirs(t) + + ebuildExtraSource = os.path.join(t, "portage-ebuild-extra-source") + with open(ebuildExtraSource, mode="w") as f: + for var_name in unexported_env_vars: + var_value = orig_env.get(var_name) + if var_value is None: + continue + f.write(f"{var_name}='{var_value}'\n") + del env[var_name] + + env["PORTAGE_EBUILD_EXTRA_SOURCE"] = str(ebuildExtraSource) + else: + env = mysettings.environ() + try: if keywords.get("returnpid") or keywords.get("returnproc"): - return spawn_func(mystring, env=mysettings.environ(), **keywords) + return spawn_func(mystring, env=env, **keywords) proc = EbuildSpawnProcess( background=False,