1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Add support for multiple locales in locale_gen (#8682)

* Add support for multiple locales in locale_gen

* Add changelog fragment

* Remove extraneous newlines

* Remove typehints

* Add 'before version' to names documentation

* Remove extraneous comment

* Replace fstring with .format

* Refer to issue in changelog fragment

Co-authored-by: Felix Fontein <felix@fontein.de>

* Clarify version

Co-authored-by: Felix Fontein <felix@fontein.de>

* Add newline between examples

Co-authored-by: Felix Fontein <felix@fontein.de>

* Use semantic markup for locale value

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
Matthias Kunnen 2024-08-12 07:33:54 +02:00 committed by GitHub
parent 8989b6c4d4
commit 158947f5e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 75 additions and 29 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- locale_gen - add support for multiple locales (https://github.com/ansible-collections/community.general/issues/8677, https://github.com/ansible-collections/community.general/pull/8682).

View file

@ -25,9 +25,11 @@ attributes:
support: none support: none
options: options:
name: name:
type: str type: list
elements: str
description: description:
- Name and encoding of the locale, such as "en_GB.UTF-8". - Name and encoding of the locales, such as V(en_GB.UTF-8).
- Before community.general 9.3.0, this was a string. Using a string still works.
required: true required: true
state: state:
type: str type: str
@ -44,6 +46,13 @@ EXAMPLES = '''
community.general.locale_gen: community.general.locale_gen:
name: de_CH.UTF-8 name: de_CH.UTF-8
state: present state: present
- name: Ensure multiple locales exist
community.general.locale_gen:
name:
- en_GB.UTF-8
- nl_NL.UTF-8
state: present
''' '''
import os import os
@ -74,7 +83,7 @@ class LocaleGen(StateModuleHelper):
output_params = ["name"] output_params = ["name"]
module = dict( module = dict(
argument_spec=dict( argument_spec=dict(
name=dict(type='str', required=True), name=dict(type="list", elements="str", required=True),
state=dict(type='str', default='present', choices=['absent', 'present']), state=dict(type='str', default='present', choices=['absent', 'present']),
), ),
supports_check_mode=True, supports_check_mode=True,
@ -91,9 +100,7 @@ class LocaleGen(StateModuleHelper):
self.LOCALE_SUPPORTED, self.LOCALE_GEN self.LOCALE_SUPPORTED, self.LOCALE_GEN
)) ))
if not self.is_available(): self.assert_available()
self.do_raise("The locale you've entered is not available on your system.")
self.vars.set("is_present", self.is_present(), output=False) self.vars.set("is_present", self.is_present(), output=False)
self.vars.set("state_tracking", self._state_name(self.vars.is_present), output=False, change=True) self.vars.set("state_tracking", self._state_name(self.vars.is_present), output=False, change=True)
@ -104,8 +111,8 @@ class LocaleGen(StateModuleHelper):
def _state_name(present): def _state_name(present):
return "present" if present else "absent" return "present" if present else "absent"
def is_available(self): def assert_available(self):
"""Check if the given locale is available on the system. This is done by """Check if the given locales are available on the system. This is done by
checking either : checking either :
* if the locale is present in /etc/locales.gen * if the locale is present in /etc/locales.gen
* or if the locale is present in /usr/share/i18n/SUPPORTED""" * or if the locale is present in /usr/share/i18n/SUPPORTED"""
@ -121,18 +128,35 @@ class LocaleGen(StateModuleHelper):
res = [re_compiled.match(line) for line in lines] res = [re_compiled.match(line) for line in lines]
if self.verbosity >= 4: if self.verbosity >= 4:
self.vars.available_lines = lines self.vars.available_lines = lines
if any(r.group("locale") == self.vars.name for r in res if r):
return True locales_not_found = []
for locale in self.vars.name:
# Check if the locale is not found in any of the matches
if not any(match and match.group("locale") == locale for match in res):
locales_not_found.append(locale)
# locale may be installed but not listed in the file, for example C.UTF-8 in some systems # locale may be installed but not listed in the file, for example C.UTF-8 in some systems
return self.is_present() locales_not_found = self.locale_get_not_present(locales_not_found)
if locales_not_found:
self.do_raise("The following locales you've entered are not available on your system: {0}".format(', '.join(locales_not_found)))
def is_present(self): def is_present(self):
return not self.locale_get_not_present(self.vars.name)
def locale_get_not_present(self, locales):
runner = locale_runner(self.module) runner = locale_runner(self.module)
with runner() as ctx: with runner() as ctx:
rc, out, err = ctx.run() rc, out, err = ctx.run()
if self.verbosity >= 4: if self.verbosity >= 4:
self.vars.locale_run_info = ctx.run_info self.vars.locale_run_info = ctx.run_info
return any(self.fix_case(self.vars.name) == self.fix_case(line) for line in out.splitlines())
not_found = []
for locale in locales:
if not any(self.fix_case(locale) == self.fix_case(line) for line in out.splitlines()):
not_found.append(locale)
return not_found
def fix_case(self, name): def fix_case(self, name):
"""locale -a might return the encoding in either lower or upper case. """locale -a might return the encoding in either lower or upper case.
@ -141,39 +165,50 @@ class LocaleGen(StateModuleHelper):
name = name.replace(s, r) name = name.replace(s, r)
return name return name
def set_locale(self, name, enabled=True): def set_locale(self, names, enabled=True):
""" Sets the state of the locale. Defaults to enabled. """ """ Sets the state of the locale. Defaults to enabled. """
search_string = r'#?\s*%s (?P<charset>.+)' % re.escape(name) with open("/etc/locale.gen", 'r') as fr:
if enabled: lines = fr.readlines()
new_string = r'%s \g<charset>' % (name)
else:
new_string = r'# %s \g<charset>' % (name)
re_search = re.compile(search_string)
with open("/etc/locale.gen", "r") as fr:
lines = [re_search.sub(new_string, line) for line in fr]
with open("/etc/locale.gen", "w") as fw:
fw.write("".join(lines))
def apply_change(self, targetState, name): locale_regexes = []
for name in names:
search_string = r'^#?\s*%s (?P<charset>.+)' % re.escape(name)
if enabled:
new_string = r'%s \g<charset>' % (name)
else:
new_string = r'# %s \g<charset>' % (name)
re_search = re.compile(search_string)
locale_regexes.append([re_search, new_string])
for i in range(len(lines)):
for [search, replace] in locale_regexes:
lines[i] = search.sub(replace, lines[i])
# Write the modified content back to the file
with open("/etc/locale.gen", 'w') as fw:
fw.writelines(lines)
def apply_change(self, targetState, names):
"""Create or remove locale. """Create or remove locale.
Keyword arguments: Keyword arguments:
targetState -- Desired state, either present or absent. targetState -- Desired state, either present or absent.
name -- Name including encoding such as de_CH.UTF-8. names -- Names list including encoding such as de_CH.UTF-8.
""" """
self.set_locale(name, enabled=(targetState == "present")) self.set_locale(names, enabled=(targetState == "present"))
runner = locale_gen_runner(self.module) runner = locale_gen_runner(self.module)
with runner() as ctx: with runner() as ctx:
ctx.run() ctx.run()
def apply_change_ubuntu(self, targetState, name): def apply_change_ubuntu(self, targetState, names):
"""Create or remove locale. """Create or remove locale.
Keyword arguments: Keyword arguments:
targetState -- Desired state, either present or absent. targetState -- Desired state, either present or absent.
name -- Name including encoding such as de_CH.UTF-8. names -- Name list including encoding such as de_CH.UTF-8.
""" """
runner = locale_gen_runner(self.module) runner = locale_gen_runner(self.module)
@ -189,7 +224,7 @@ class LocaleGen(StateModuleHelper):
with open("/var/lib/locales/supported.d/local", "w") as fw: with open("/var/lib/locales/supported.d/local", "w") as fw:
for line in content: for line in content:
locale, charset = line.split(' ') locale, charset = line.split(' ')
if locale != name: if locale not in names:
fw.write(line) fw.write(line)
# Purge locales and regenerate. # Purge locales and regenerate.
# Please provide a patch if you know how to avoid regenerating the locales to keep! # Please provide a patch if you know how to avoid regenerating the locales to keep!

View file

@ -15,3 +15,12 @@ locale_list_basic:
- localegen: eo - localegen: eo
locales: [eo] locales: [eo]
skip_removal: false skip_removal: false
- localegen:
- ar_BH.UTF-8
- tr_CY.UTF-8
locales:
- ar_BH.UTF-8
- ar_BH.utf8
- tr_CY.UTF-8
- tr_CY.utf8
skip_removal: false