diff options
author | Zac Medico <zmedico@gentoo.org> | 2024-02-08 22:38:41 -0800 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2024-02-09 00:19:00 -0800 |
commit | c95fc64abf9698263090b3ffd4a056e989dd2be1 (patch) | |
tree | d80b59edddd71d254dcf480d215f7a65ebaafb3e /lib/portage | |
parent | check_locale: Use multiprocessing.Process instead of os.fork() (diff) | |
download | portage-c95fc64abf9698263090b3ffd4a056e989dd2be1.tar.gz portage-c95fc64abf9698263090b3ffd4a056e989dd2be1.tar.bz2 portage-c95fc64abf9698263090b3ffd4a056e989dd2be1.zip |
EbuildPhase: async_check_locale
Change config.environ() check_locale calls to async_check_locale
calls in the EbuildPhase _async_start method in order to eliminate
synchronous waiting for child processes in the main event loop
thread.
Bug: https://bugs.gentoo.org/923841
Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib/portage')
-rw-r--r-- | lib/portage/package/ebuild/config.py | 26 | ||||
-rw-r--r-- | lib/portage/util/futures/_asyncio/__init__.py | 9 | ||||
-rw-r--r-- | lib/portage/util/locale.py | 28 |
3 files changed, 39 insertions, 24 deletions
diff --git a/lib/portage/package/ebuild/config.py b/lib/portage/package/ebuild/config.py index d7b0ca567..35c77486e 100644 --- a/lib/portage/package/ebuild/config.py +++ b/lib/portage/package/ebuild/config.py @@ -29,7 +29,6 @@ portage.proxy.lazyimport.lazyimport( "portage.dbapi.vartree:vartree", "portage.package.ebuild.doebuild:_phase_func_map", "portage.util.compression_probe:_compressors", - "portage.util.locale:check_locale,split_LC_ALL", ) from portage import bsd_chflags, load_mod, os, selinux, _unicode_decode from portage.const import ( @@ -3368,20 +3367,17 @@ class config: mydict["EBUILD_PHASE_FUNC"] = phase_func if eapi_attrs.posixish_locale: - split_LC_ALL(mydict) - mydict["LC_COLLATE"] = "C" - # check_locale() returns None when check can not be executed. - if check_locale(silent=True, env=mydict) is False: - # try another locale - for l in ("C.UTF-8", "en_US.UTF-8", "en_GB.UTF-8", "C"): - mydict["LC_CTYPE"] = l - if check_locale(silent=True, env=mydict): - # TODO: output the following only once - # writemsg(_("!!! LC_CTYPE unsupported, using %s instead\n") - # % mydict["LC_CTYPE"]) - break - else: - raise AssertionError("C locale did not pass the test!") + if mydict.get("LC_ALL"): + # Sometimes this method is called for processes + # that are not ebuild phases, so only raise + # AssertionError for actual ebuild phases. + if phase and phase not in ("clean", "cleanrm", "fetch"): + raise AssertionError( + f"LC_ALL={mydict['LC_ALL']} for posixish locale. It seems that split_LC_ALL was not called for phase {phase}?" + ) + elif "LC_ALL" in mydict: + # Delete placeholder from split_LC_ALL. + del mydict["LC_ALL"] if not eapi_attrs.exports_PORTDIR: mydict.pop("PORTDIR", None) diff --git a/lib/portage/util/futures/_asyncio/__init__.py b/lib/portage/util/futures/_asyncio/__init__.py index 8f1b8e827..e78686bc5 100644 --- a/lib/portage/util/futures/_asyncio/__init__.py +++ b/lib/portage/util/futures/_asyncio/__init__.py @@ -15,6 +15,7 @@ __all__ = ( "set_child_watcher", "get_event_loop_policy", "set_event_loop_policy", + "run", "shield", "sleep", "Task", @@ -106,6 +107,14 @@ def set_child_watcher(watcher): return get_event_loop_policy().set_child_watcher(watcher) +# Emulate run since it's the preferred python API. +def run(coro): + return _safe_loop().run_until_complete(coro) + + +run.__doc__ = _real_asyncio.run.__doc__ + + def create_subprocess_exec(*args, **kwargs): """ Create a subprocess. diff --git a/lib/portage/util/locale.py b/lib/portage/util/locale.py index b5da8d949..b6a41e765 100644 --- a/lib/portage/util/locale.py +++ b/lib/portage/util/locale.py @@ -17,6 +17,7 @@ import traceback import portage from portage.util import _unicode_decode, writemsg_level from portage.util._ctypes import find_library, LoadLibrary +from portage.util.futures import asyncio locale_categories = ( @@ -121,7 +122,10 @@ def check_locale(silent=False, env=None): warning and returns False if it is not. Returns None if the check can not be executed due to platform limitations. """ + return asyncio.run(async_check_locale(silent=silent, env=env)) + +async def async_check_locale(silent=False, env=None): if env is not None: for v in ("LC_ALL", "LC_CTYPE", "LANG"): if v in env: @@ -135,20 +139,17 @@ def check_locale(silent=False, env=None): except KeyError: pass - # TODO: Make async version of check_locale and call it from - # EbuildPhase instead of config.environ(), since it's bad to - # synchronously wait for the process in the main event loop - # thread where config.environ() tends to be called. proc = multiprocessing.Process( target=_set_and_check_locale, args=(silent, env, None if env is None else portage._native_string(mylocale)), ) proc.start() - proc.join() + proc = portage.process.MultiprocessingProcess(proc) + await proc.wait() pyret = None - if proc.exitcode >= 0: - ret = proc.exitcode + if proc.returncode >= 0: + ret = proc.returncode if ret != 2: pyret = ret == 0 @@ -157,13 +158,22 @@ def check_locale(silent=False, env=None): return pyret +async_check_locale.__doc__ = check_locale.__doc__ +async_check_locale.__doc__ += """ + This function is a coroutine. +""" + + def split_LC_ALL(env): """ Replace LC_ALL with split-up LC_* variables if it is defined. Works on the passed environment (or settings instance). """ lc_all = env.get("LC_ALL") - if lc_all is not None: + if lc_all: for c in locale_categories: env[c] = lc_all - del env["LC_ALL"] + # Set empty so that config.reset() can restore LC_ALL state, + # since del can permanently delete variables which are not + # stored in the config's backupenv. + env["LC_ALL"] = "" |