From 43eb342b180e550ea1742da88377e46e4e94c170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sibe=20Bleuz=C3=A9?= Date: Sat, 10 May 2025 13:21:36 +0200 Subject: [PATCH] ini_file: fix unmatched whitespace before comment (#10102) * ini_file: fix unmatched whitespace before comment * Add changelog fragment * Update changelog fragment: bugfixes to minor_changes Co-authored-by: Felix Fontein --------- Co-authored-by: sibebleuze <> Co-authored-by: Felix Fontein --- ...ix-unmatched-whitespace-before-comment.yml | 2 + plugins/modules/ini_file.py | 16 +++---- .../tasks/tests/06-modify_inactive_option.yml | 44 ++++++++++++++++++- 3 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 changelogs/fragments/10102-ini_file-fix-unmatched-whitespace-before-comment.yml diff --git a/changelogs/fragments/10102-ini_file-fix-unmatched-whitespace-before-comment.yml b/changelogs/fragments/10102-ini_file-fix-unmatched-whitespace-before-comment.yml new file mode 100644 index 0000000000..75c7c40299 --- /dev/null +++ b/changelogs/fragments/10102-ini_file-fix-unmatched-whitespace-before-comment.yml @@ -0,0 +1,2 @@ +minor_changes: + - ini_file - modify an inactive option also when there are spaces in front of the comment symbol (https://github.com/ansible-collections/community.general/pull/10102, https://github.com/ansible-collections/community.general/issues/8539). diff --git a/plugins/modules/ini_file.py b/plugins/modules/ini_file.py index 61e6662d95..bf8534bf39 100644 --- a/plugins/modules/ini_file.py +++ b/plugins/modules/ini_file.py @@ -268,21 +268,21 @@ from ansible.module_utils.common.text.converters import to_bytes, to_text def match_opt(option, line): option = re.escape(option) - return re.match('([#;]?)( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line) + return re.match('( |\t)*([#;]?)( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line) def match_active_opt(option, line): option = re.escape(option) - return re.match('()( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line) + return re.match('()()( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line) def update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg): option_changed = None if ignore_spaces: old_match = match_opt(option, section_lines[index]) - if not old_match.group(1): + if not old_match.group(2): new_match = match_opt(option, newline) - option_changed = old_match.group(7) != new_match.group(7) + option_changed = old_match.group(8) != new_match.group(8) if option_changed is None: option_changed = section_lines[index] != newline if option_changed: @@ -299,7 +299,7 @@ def check_section_has_values(section_has_values, section_lines): for condition in section_has_values: for line in section_lines: match = match_opt(condition["option"], line) - if match and (len(condition["values"]) == 0 or match.group(7) in condition["values"]): + if match and (len(condition["values"]) == 0 or match.group(8) in condition["values"]): break else: return False @@ -432,8 +432,8 @@ def do_ini(module, filename, section=None, section_has_values=None, option=None, for index, line in enumerate(section_lines): if match_function(option, line): match = match_function(option, line) - if values and match.group(7) in values: - matched_value = match.group(7) + if values and match.group(8) in values: + matched_value = match.group(8) if not matched_value and allow_no_value: # replace existing option with no value line(s) newline = u'%s\n' % option @@ -505,7 +505,7 @@ def do_ini(module, filename, section=None, section_has_values=None, option=None, section_lines = new_section_lines elif not exclusive and len(values) > 0: # delete specified option=value line(s) - new_section_lines = [i for i in section_lines if not (match_active_opt(option, i) and match_active_opt(option, i).group(7) in values)] + new_section_lines = [i for i in section_lines if not (match_active_opt(option, i) and match_active_opt(option, i).group(8) in values)] if section_lines != new_section_lines: changed = True msg = 'option changed' diff --git a/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml b/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml index 2d1d049281..4869b95119 100644 --- a/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml +++ b/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml @@ -120,4 +120,46 @@ that: - result3 is changed - result3.msg == 'option changed' - - content3 == expected3 \ No newline at end of file + - content3 == expected3 + + +- name: test-modify_inactive_option 4 - create test file with spaces before commented option + copy: + content: | + + [section1] + # Uncomment the line below to enable foo + # foo = bar + + dest: "{{ output_file }}" + +- name: test-modify_inactive_option 4 - set value for foo with modify_inactive_option set to true + ini_file: + path: "{{ output_file }}" + section: section1 + option: foo + value: bar + modify_inactive_option: true + register: result4 + +- name: test-modify_inactive_option 4 - read content from output file + slurp: + src: "{{ output_file }}" + register: output_content + +- name: test-modify_inactive_option 4 - set expected content and get current ini file content + set_fact: + expected4: | + + [section1] + # Uncomment the line below to enable foo + foo = bar + + content4: "{{ output_content.content | b64decode }}" + +- name: test-modify_inactive_option 4 - assert 'changed' is true and content is OK and option changed + assert: + that: + - result4 is changed + - result4.msg == 'option changed' + - content4 == expected4