Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions plugins/modules/locale_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
ETC_LOCALE_GEN = "/etc/locale.gen"
VAR_LIB_LOCALES = "/var/lib/locales/supported.d"
VAR_LIB_LOCALES_LOCAL = os.path.join(VAR_LIB_LOCALES, "local")
SUPPORTED_LOCALES = "/usr/share/i18n/SUPPORTED"
SUPPORTED_LOCALES = ["/usr/share/i18n/SUPPORTED", "/usr/local/share/i18n/SUPPORTED"]
LOCALE_NORMALIZATION = {
".utf8": ".UTF-8",
".eucjp": ".EUC-JP",
Expand All @@ -111,7 +111,7 @@ class LocaleGen(StateModuleHelper):
)

def __init_module__(self):
self.MECHANISMS = dict(
self.mechanisms = dict(
ubuntu_legacy=dict(
available=SUPPORTED_LOCALES,
apply_change=self.apply_change_ubuntu_legacy,
Expand Down Expand Up @@ -156,19 +156,21 @@ def assert_available(self):
checking either :
* if the locale is present in /etc/locales.gen
* or if the locale is present in /usr/share/i18n/SUPPORTED"""
regexp = r"^\s*#?\s*(?P<locale>\S+[\._\S]+) (?P<charset>\S+)\s*$"
locales_available = self.MECHANISMS[self.vars.mechanism]["available"]

re_compiled = re.compile(regexp)
with open(locales_available, "r") as fd:
lines = fd.readlines()
res = [re_compiled.match(line) for line in lines]
self.vars.set("available_lines", lines, verbosity=4)
self.vars.set("available_lines", [], verbosity=4)
available_locale_entry_re_matches = []
for locale_path in self.mechanisms[self.vars.mechanism]["available"]:
if os.path.exists(locale_path):
with open(locale_path, "r") as fd:
self.vars.available_lines.extend(fd.readlines())

re_locale_entry = re.compile(r"^\s*#?\s*(?P<locale>\S+[\._\S]+) (?P<charset>\S+)\s*$")
available_locale_entry_re_matches.extend([re_locale_entry.match(line) for line in self.vars.available_lines])

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):
if not any(match and match.group("locale") == locale for match in available_locale_entry_re_matches):
locales_not_found.append(locale)

# locale may be installed but not listed in the file, for example C.UTF-8 in some systems
Expand Down Expand Up @@ -219,38 +221,41 @@ def set_locale_glibc(self, names, enabled=True):
re_search = re.compile(search_string)
locale_regexes.append([re_search, new_string])

for i in range(len(lines)):
def search_replace(line):
for [search, replace] in locale_regexes:
lines[i] = search.sub(replace, lines[i])
line = search.sub(replace, line)
return line

lines = [search_replace(line) for line in lines]

# Write the modified content back to the file
with open(ETC_LOCALE_GEN, "w") as fw:
fw.writelines(lines)

def apply_change_glibc(self, targetState, names):
def apply_change_glibc(self, target_state, names):
"""Create or remove locale.

Keyword arguments:
targetState -- Desired state, either present or absent.
target_state -- Desired state, either present or absent.
names -- Names list including encoding such as de_CH.UTF-8.
"""

self.set_locale_glibc(names, enabled=(targetState == "present"))
self.set_locale_glibc(names, enabled=(target_state == "present"))

runner = locale_gen_runner(self.module)
with runner() as ctx:
ctx.run()

def apply_change_ubuntu_legacy(self, targetState, names):
def apply_change_ubuntu_legacy(self, target_state, names):
"""Create or remove locale.

Keyword arguments:
targetState -- Desired state, either present or absent.
target_state -- Desired state, either present or absent.
names -- Name list including encoding such as de_CH.UTF-8.
"""
runner = locale_gen_runner(self.module)

if targetState == "present":
if target_state == "present":
# Create locale.
# Ubuntu's patched locale-gen automatically adds the new locale to /var/lib/locales/supported.d/local
with runner() as ctx:
Expand All @@ -273,7 +278,7 @@ def apply_change_ubuntu_legacy(self, targetState, names):
def __state_fallback__(self):
if self.vars.state_tracking == self.vars.state:
return
self.MECHANISMS[self.vars.mechanism]["apply_change"](self.vars.state, self.vars.name)
self.mechanisms[self.vars.mechanism]["apply_change"](self.vars.state, self.vars.name)


def main():
Expand Down
120 changes: 120 additions & 0 deletions tests/integration/targets/locale_gen/files/en_US@iso
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to add a [email protected] file next to it with a license header, or add it as a comment at the top of this file.

Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
comment_char %
escape_char /

% This file is part of the GNU C Library and contains locale data.
% The Free Software Foundation does not claim any copyright interest
% in the locale data contained in this file. The foregoing does not
% affect the license of the GNU C Library as a whole. It does not
% exempt you from the conditions of the license if your use would
% otherwise be governed by that license.

LC_IDENTIFICATION
title "English locale for the USA with ISO formats"
language "American English"

category "i18n:2012";LC_IDENTIFICATION
category "i18n:2012";LC_CTYPE
category "i18n:2012";LC_COLLATE
category "i18n:2012";LC_TIME
category "i18n:2012";LC_NUMERIC
category "i18n:2012";LC_MONETARY
category "i18n:2012";LC_MESSAGES
category "i18n:2012";LC_PAPER
category "i18n:2012";LC_NAME
category "i18n:2012";LC_ADDRESS
category "i18n:2012";LC_TELEPHONE
category "i18n:2012";LC_MEASUREMENT
END LC_IDENTIFICATION

LC_TIME
day "Sunday";/
"Monday";/
"Tuesday";/
"Wednesday";/
"Thursday";/
"Friday";/
"Saturday"
abday "Sun";/
"Mon";/
"Tue";/
"Wed";/
"Thu";/
"Fri";/
"Sat"

mon "January";/
"February";/
"March";/
"April";/
"May";/
"June";/
"July";/
"August";/
"September";/
"October";/
"November";/
"December"
abmon "Jan";/
"Feb";/
"Mar";/
"Apr";/
"May";/
"Jun";/
"Jul";/
"Aug";/
"Sep";/
"Oct";/
"Nov";/
"Dec"

date_fmt "%a %d %b %Y %T %Z"
d_t_fmt "%a %d %b %Y %T"
d_fmt "%Y-%m-%d"
t_fmt "%T"
t_fmt_ampm ""
am_pm "";""
week 7;19971130;4
first_weekday 2
END LC_TIME

LC_CTYPE
copy "en_US"
END LC_CTYPE

LC_COLLATE
copy "en_US"
END LC_COLLATE

LC_MONETARY
copy "en_US"
END LC_MONETARY

LC_NUMERIC
decimal_point "."
thousands_sep ","
grouping 3;3
END LC_NUMERIC

LC_MESSAGES
copy "en_US"
END LC_MESSAGES

LC_PAPER
copy "i18n"
END LC_PAPER

LC_TELEPHONE
copy "en_US"
END LC_TELEPHONE

LC_MEASUREMENT
copy "i18n"
END LC_MEASUREMENT

LC_NAME
copy "en_US"
END LC_NAME

LC_ADDRESS
copy "en_US"
END LC_ADDRESS
79 changes: 79 additions & 0 deletions tests/integration/targets/locale_gen/tasks/11046-usrlocal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

- name: Is the locale we're going to test against installed?
command: locale -a
register: initial_state

- name: Make sure the locale is not installed (BEGIN)
community.general.locale_gen:
name: en_US@iso
state: absent
ignore_errors: true
register: not_available

- name: Ensure /usr/local/share/i18n/
ansible.builtin.file:
path: /usr/local/share/i18n/locales
state: directory
mode: '0755'

- name: Back up /etc/locale.gen
ansible.builtin.copy:
src: /etc/locale.gen
dest: /etc/locale.gen.bkp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
dest: /etc/locale.gen.bkp
dest: /etc/locale.gen.bkp
remote_src: true


- name: Add line to /etc/locale.gen
ansible.builtin.shell: >
echo "# en_US@iso UTF-8" >> /etc/locale.gen

- name: Copy custom locale
ansible.builtin.copy:
dest: /usr/local/share/i18n/locales/en_US@iso
src: en_US@iso
mode: '0644'

- name: Add custom locale to SUPPORTED
ansible.builtin.copy:
dest: /usr/local/share/i18n/SUPPORTED
content: |
en_US@iso UTF-8
mode: '0644'

- name: Make sure the locale is available
community.general.locale_gen:
name: en_US@iso
state: absent
register: available

- name: Make sure the locale is installed
community.general.locale_gen:
name: en_US@iso
state: present
register: installed

- name: Check assertions
ansible.builtin.assert:
that:
- not_available is failed
- >
"locales you have entered are not available on your system: en_US@iso" in not_available.msg
- available is not changed
- installed is changed

- name: Make sure the locale is not installed (END)
community.general.locale_gen:
name: en_US@iso
state: absent

- name: Remove /usr/local/share/i18n/
ansible.builtin.file:
path: /usr/local/share/i18n/
state: absent

- name: Restore /etc/locale.gen
ansible.builtin.copy:
src: /etc/locale.gen.bkp
dest: /etc/locale.gen
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
dest: /etc/locale.gen
dest: /etc/locale.gen
remote_src: true

3 changes: 3 additions & 0 deletions tests/integration/targets/locale_gen/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@
loop: "{{ locale_list_basic }}"
loop_control:
loop_var: locale_basic

- name: Run tests for 11046
ansible.builtin.include_tasks: 11046-usrlocal.yml
Loading