diff --git a/changelogs/fragments/6774-locale-gen-fix.yml b/changelogs/fragments/6774-locale-gen-fix.yml new file mode 100644 index 0000000000..fc71022f06 --- /dev/null +++ b/changelogs/fragments/6774-locale-gen-fix.yml @@ -0,0 +1,2 @@ +bugfixes: + - locale_gen - now works for locales without the underscore character such as ``C.UTF-8`` (https://github.com/ansible-collections/community.general/pull/6774, https://github.com/ansible-collections/community.general/issues/5142, https://github.com/ansible-collections/community.general/issues/4305). diff --git a/plugins/modules/locale_gen.py b/plugins/modules/locale_gen.py index fccdf977a4..36c304ea69 100644 --- a/plugins/modules/locale_gen.py +++ b/plugins/modules/locale_gen.py @@ -35,6 +35,8 @@ options: - Whether the locale shall be present. choices: [ absent, present ] default: present +notes: + - This module does not support RHEL-based systems. ''' EXAMPLES = ''' @@ -74,11 +76,10 @@ def is_available(name, ubuntuMode): 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*(?P\S+[\._\S]*) (?P\S+)\s*$' if ubuntuMode: - __regexp = r'^(?P\S+_\S+) (?P\S+)\s*$' __locales_available = '/usr/share/i18n/SUPPORTED' else: - __regexp = r'^#{0,1}\s*(?P\S+_\S+) (?P\S+)\s*$' __locales_available = '/etc/locale.gen' re_compiled = re.compile(__regexp) @@ -88,7 +89,8 @@ def is_available(name, ubuntuMode): if result and result.group('locale') == name: return True fd.close() - return False + # locale may be installed but not listed in the file, for example C.UTF-8 in some systems + return is_present(name) def is_present(name): @@ -106,20 +108,6 @@ def fix_case(name): return name -def replace_line(existing_line, new_line): - """Replaces lines in /etc/locale.gen""" - try: - f = open("/etc/locale.gen", "r") - lines = [line.replace(existing_line, new_line) for line in f] - finally: - f.close() - try: - f = open("/etc/locale.gen", "w") - f.write("".join(lines)) - finally: - f.close() - - def set_locale(name, enabled=True): """ Sets the state of the locale. Defaults to enabled. """ search_string = r'#{0,1}\s*%s (?P.+)' % name @@ -209,7 +197,7 @@ def main(): # We found the common way to manage locales. ubuntuMode = False else: - module.fail_json(msg="/etc/locale.gen and /var/lib/locales/supported.d/local are missing. Is the package \"locales\" installed?") + module.fail_json(msg="/etc/locale.gen and /var/lib/locales/supported.d/local are missing. Is the package 'locales' installed?") else: # Ubuntu created its own system to manage locales. ubuntuMode = True diff --git a/tests/integration/targets/locale_gen/aliases b/tests/integration/targets/locale_gen/aliases index f7f4063f6c..a5d3e27f9e 100644 --- a/tests/integration/targets/locale_gen/aliases +++ b/tests/integration/targets/locale_gen/aliases @@ -6,3 +6,5 @@ azp/posix/3 destructive needs/root skip/aix +skip/freebsd +skip/macos diff --git a/tests/integration/targets/locale_gen/tasks/basic.yml b/tests/integration/targets/locale_gen/tasks/basic.yml new file mode 100644 index 0000000000..8718e0be8b --- /dev/null +++ b/tests/integration/targets/locale_gen/tasks/basic.yml @@ -0,0 +1,102 @@ +--- +# 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? {{ locale_basic.localegen }} + command: locale -a + register: initial_state + ignore_errors: true + +- name: Make sure the locale is not installed {{ locale_basic.localegen }} + locale_gen: + name: "{{ locale_basic.localegen }}" + state: absent + +- name: Is the locale present? {{ locale_basic.localegen }} + command: locale -a + register: cleaned + ignore_errors: true + +- name: Make sure the locale is not present {{ locale_basic.localegen }} + assert: + that: + - locale_basic.skip_removal or locale_basic.locales | intersect(cleaned.stdout_lines) == [] + +- name: Install the locale {{ locale_basic.localegen }} + locale_gen: + name: "{{ locale_basic.localegen }}" + state: present + register: output_present + +- name: Is the locale present? {{ locale_basic.localegen }} + command: locale -a + register: post_check_output_present + ignore_errors: true + +- name: Make sure the locale is present and we say we installed it {{ locale_basic.localegen }} + assert: + that: + - locale_basic.locales | intersect(post_check_output_present.stdout_lines) != [] + - locale_basic.skip_removal or output_present is changed + +- name: Install the locale a second time {{ locale_basic.localegen }} + locale_gen: + name: "{{ locale_basic.localegen }}" + state: present + register: output_present_idempotent + +- name: Is the locale present? {{ locale_basic.localegen }} + command: locale -a + register: post_check_output_present_idempotent + ignore_errors: true + +- name: Make sure the locale is present and we reported no change {{ locale_basic.localegen }} + assert: + that: + - locale_basic.locales | intersect(post_check_output_present_idempotent.stdout_lines) != [] + - output_present_idempotent is not changed + +- name: Removals + when: locale_basic.skip_removal is false + block: + - name: Remove the locale {{ locale_basic.localegen }} + locale_gen: + name: "{{ locale_basic.localegen }}" + state: absent + register: output_absent + + - name: Is the locale present? {{ locale_basic.localegen }} + command: locale -a + register: post_check_output_absent + ignore_errors: true + + - name: Make sure the locale is absent and we reported a change {{ locale_basic.localegen }} + assert: + that: + - locale_basic.locales | intersect(post_check_output_absent.stdout_lines) == [] + - output_absent is changed + + - name: Remove the locale a second time {{ locale_basic.localegen }} + locale_gen: + name: "{{ locale_basic.localegen }}" + state: absent + register: output_absent_idempotent + + - name: Is the locale present? {{ locale_basic.localegen }} + command: locale -a + register: post_check_output_absent_idempotent + ignore_errors: true + + - name: Make sure the locale is absent and we reported no change {{ locale_basic.localegen }} + assert: + that: + - locale_basic.locales | intersect(post_check_output_absent_idempotent.stdout_lines) == [] + - output_absent_idempotent is not changed + +# Cleanup +- name: Reinstall the locale we tested against if it was initially installed {{ locale_basic.localegen }} + locale_gen: + name: "{{ locale_basic.localegen }}" + state: present + when: locale_basic.locales | intersect(initial_state.stdout_lines) != [] diff --git a/tests/integration/targets/locale_gen/tasks/locale_gen.yml b/tests/integration/targets/locale_gen/tasks/locale_gen.yml deleted file mode 100644 index c6bdcc046b..0000000000 --- a/tests/integration/targets/locale_gen/tasks/locale_gen.yml +++ /dev/null @@ -1,99 +0,0 @@ ---- -# 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? - shell: locale -a | grep pt_BR - register: initial_state - ignore_errors: true - -- name: Make sure the locale is not installed - locale_gen: - name: pt_BR - state: absent - -- name: Is the locale present? - shell: locale -a | grep pt_BR - register: cleaned - ignore_errors: true - -- name: Make sure the locale is not present - assert: - that: - - "cleaned.rc == 1" - -- name: Install the locale - locale_gen: - name: pt_BR - state: present - register: output - -- name: Is the locale present? - shell: locale -a | grep pt_BR - register: post_check_output - ignore_errors: true - -- name: Make sure the locale is present and we say we installed it - assert: - that: - - "post_check_output.rc == 0" - - "output.changed" - -- name: Install the locale a second time - locale_gen: - name: pt_BR - state: present - register: output - -- name: Is the locale present? - shell: locale -a | grep pt_BR - register: post_check_output - ignore_errors: true - -- name: Make sure the locale is present and we reported no change - assert: - that: - - "post_check_output.rc == 0" - - "not output.changed" - -- name: Remove the locale - locale_gen: - name: pt_BR - state: absent - register: output - -- name: Is the locale present? - shell: locale -a | grep pt_BR - register: post_check_output - ignore_errors: true - -- name: Make sure the locale is absent and we reported a change - assert: - that: - - "post_check_output.rc == 1" - - "output.changed" - -- name: Remove the locale a second time - locale_gen: - name: pt_BR - state: absent - register: output - -- name: Is the locale present? - shell: locale -a | grep pt_BR - register: post_check_output - ignore_errors: true - -- name: Make sure the locale is absent and we reported no change - assert: - that: - - "post_check_output.rc == 1" - - "not output.changed" - -# Cleanup -- name: Reinstall the locale we tested against if it was initially installed - locale_gen: - name: pt_BR - state: present - when: initial_state.rc == 0 diff --git a/tests/integration/targets/locale_gen/tasks/main.yml b/tests/integration/targets/locale_gen/tasks/main.yml index de3e673beb..2d9dfcee04 100644 --- a/tests/integration/targets/locale_gen/tasks/main.yml +++ b/tests/integration/targets/locale_gen/tasks/main.yml @@ -8,5 +8,11 @@ # 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 -- include_tasks: 'locale_gen.yml' - when: ansible_distribution in ('Ubuntu', 'Debian') +- name: Bail out if not supported + ansible.builtin.meta: end_play + when: ansible_distribution not in ('Ubuntu', 'Debian') + +- include_tasks: basic.yml + loop: "{{ locale_list_basic }}" + loop_control: + loop_var: locale_basic diff --git a/tests/integration/targets/locale_gen/vars/main.yml b/tests/integration/targets/locale_gen/vars/main.yml new file mode 100644 index 0000000000..44327ddd31 --- /dev/null +++ b/tests/integration/targets/locale_gen/vars/main.yml @@ -0,0 +1,17 @@ +--- +# 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 + +# locale_basic: pt_BR + +locale_list_basic: + - localegen: pt_BR + locales: [pt_BR] + skip_removal: false + - localegen: C.UTF-8 + locales: [C.utf8, C.UTF-8] + skip_removal: true + - localegen: eo + locales: [eo] + skip_removal: false