|
|
|
"""Initialize locale settings. This must be imported very early in ansible-test startup."""
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import locale
|
|
|
|
import sys
|
|
|
|
import typing as t
|
|
|
|
|
|
|
|
STANDARD_LOCALE = 'en_US.UTF-8'
|
|
|
|
"""
|
|
|
|
The standard locale used by ansible-test and its subprocesses and delegated instances.
|
|
|
|
"""
|
|
|
|
|
|
|
|
FALLBACK_LOCALE = 'C.UTF-8'
|
|
|
|
"""
|
|
|
|
The fallback locale to use when the standard locale is not available.
|
|
|
|
This was added in ansible-core 2.14 to allow testing in environments without the standard locale.
|
|
|
|
It was not needed in previous ansible-core releases since they do not verify the locale during startup.
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
class LocaleError(SystemExit):
|
|
|
|
"""Exception to raise when locale related errors occur."""
|
|
|
|
|
|
|
|
def __init__(self, message: str) -> None:
|
|
|
|
super().__init__(f'ERROR: {message}')
|
|
|
|
|
|
|
|
|
|
|
|
def configure_locale() -> tuple[str, t.Optional[str]]:
|
|
|
|
"""Configure the locale, returning the selected locale and an optional warning."""
|
|
|
|
|
|
|
|
if (fs_encoding := sys.getfilesystemencoding()).lower() != 'utf-8':
|
|
|
|
raise LocaleError(f'ansible-test requires the filesystem encoding to be UTF-8, but "{fs_encoding}" was detected.')
|
|
|
|
|
|
|
|
candidate_locales = STANDARD_LOCALE, FALLBACK_LOCALE
|
|
|
|
|
|
|
|
errors: dict[str, str] = {}
|
|
|
|
warning: t.Optional[str] = None
|
|
|
|
configured_locale: t.Optional[str] = None
|
|
|
|
|
|
|
|
for candidate_locale in candidate_locales:
|
|
|
|
try:
|
|
|
|
locale.setlocale(locale.LC_ALL, candidate_locale)
|
|
|
|
locale.getlocale()
|
|
|
|
except (locale.Error, ValueError) as ex:
|
|
|
|
errors[candidate_locale] = str(ex)
|
|
|
|
else:
|
|
|
|
configured_locale = candidate_locale
|
|
|
|
break
|
|
|
|
|
|
|
|
if not configured_locale:
|
|
|
|
raise LocaleError('ansible-test could not initialize a supported locale:\n' +
|
|
|
|
'\n'.join(f'{key}: {value}' for key, value in errors.items()))
|
|
|
|
|
|
|
|
if configured_locale != STANDARD_LOCALE:
|
|
|
|
warning = (f'Using locale "{configured_locale}" instead of "{STANDARD_LOCALE}". '
|
|
|
|
'Tests which depend on the locale may behave unexpectedly.')
|
|
|
|
|
|
|
|
return configured_locale, warning
|
|
|
|
|
|
|
|
|
|
|
|
CONFIGURED_LOCALE, LOCALE_WARNING = configure_locale()
|