mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Add modify_inactive_option
option to ini_file
module to ignore matching commented key:value pairs (#7401)
* Add `modify_inactive_option` option to `ini_file` module to ignore matching commented key:value pairs * Add changelog fragment * Apply suggestions from code review Co-authored-by: Felix Fontein <felix@fontein.de> * Minor comment fix * Apply suggestions from code review Co-authored-by: Felix Fontein <felix@fontein.de> --------- Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
714e06089e
commit
6ee1f27304
4 changed files with 152 additions and 8 deletions
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- ini_file - add ``modify_inactive_option`` option (https://github.com/ansible-collections/community.general/pull/7401).
|
|
@ -116,6 +116,14 @@ options:
|
|||
- Allow option without value and without '=' symbol.
|
||||
type: bool
|
||||
default: false
|
||||
modify_inactive_option:
|
||||
description:
|
||||
- By default the module replaces a commented line that matches the given option.
|
||||
- Set this option to V(false) to avoid this. This is useful when you want to keep commented example
|
||||
C(key=value) pairs for documentation purposes.
|
||||
type: bool
|
||||
default: true
|
||||
version_added: 8.0.0
|
||||
follow:
|
||||
description:
|
||||
- This flag indicates that filesystem links, if they exist, should be followed.
|
||||
|
@ -190,7 +198,7 @@ def match_opt(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):
|
||||
|
@ -213,7 +221,7 @@ def update_section_line(option, changed, section_lines, index, changed_lines, ig
|
|||
|
||||
def do_ini(module, filename, section=None, option=None, values=None,
|
||||
state='present', exclusive=True, backup=False, no_extra_spaces=False,
|
||||
ignore_spaces=False, create=True, allow_no_value=False, follow=False):
|
||||
ignore_spaces=False, create=True, allow_no_value=False, modify_inactive_option=True, follow=False):
|
||||
|
||||
if section is not None:
|
||||
section = to_text(section)
|
||||
|
@ -310,6 +318,12 @@ def do_ini(module, filename, section=None, option=None, values=None,
|
|||
# Keep track of changed section_lines
|
||||
changed_lines = [0] * len(section_lines)
|
||||
|
||||
# Determine whether to consider using commented out/inactive options or only active ones
|
||||
if modify_inactive_option:
|
||||
match_function = match_opt
|
||||
else:
|
||||
match_function = match_active_opt
|
||||
|
||||
# handling multiple instances of option=value when state is 'present' with/without exclusive is a bit complex
|
||||
#
|
||||
# 1. edit all lines where we have a option=value pair with a matching value in values[]
|
||||
|
@ -319,8 +333,8 @@ def do_ini(module, filename, section=None, option=None, values=None,
|
|||
|
||||
if state == 'present' and option:
|
||||
for index, line in enumerate(section_lines):
|
||||
if match_opt(option, line):
|
||||
match = match_opt(option, line)
|
||||
if match_function(option, line):
|
||||
match = match_function(option, line)
|
||||
if values and match.group(7) in values:
|
||||
matched_value = match.group(7)
|
||||
if not matched_value and allow_no_value:
|
||||
|
@ -343,14 +357,14 @@ def do_ini(module, filename, section=None, option=None, values=None,
|
|||
# override option with no value to option with value if not allow_no_value
|
||||
if len(values) > 0:
|
||||
for index, line in enumerate(section_lines):
|
||||
if not changed_lines[index] and match_opt(option, line):
|
||||
if not changed_lines[index] and match_function(option, line):
|
||||
newline = assignment_format % (option, values.pop(0))
|
||||
(changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
|
||||
if len(values) == 0:
|
||||
break
|
||||
# remove all remaining option occurrences from the rest of the section
|
||||
for index in range(len(section_lines) - 1, 0, -1):
|
||||
if not changed_lines[index] and match_opt(option, section_lines[index]):
|
||||
if not changed_lines[index] and match_function(option, section_lines[index]):
|
||||
del section_lines[index]
|
||||
del changed_lines[index]
|
||||
changed = True
|
||||
|
@ -394,7 +408,7 @@ def do_ini(module, filename, section=None, option=None, values=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(6) 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(7) in values)]
|
||||
if section_lines != new_section_lines:
|
||||
changed = True
|
||||
msg = 'option changed'
|
||||
|
@ -466,6 +480,7 @@ def main():
|
|||
no_extra_spaces=dict(type='bool', default=False),
|
||||
ignore_spaces=dict(type='bool', default=False),
|
||||
allow_no_value=dict(type='bool', default=False),
|
||||
modify_inactive_option=dict(type='bool', default=True),
|
||||
create=dict(type='bool', default=True),
|
||||
follow=dict(type='bool', default=False)
|
||||
),
|
||||
|
@ -487,6 +502,7 @@ def main():
|
|||
no_extra_spaces = module.params['no_extra_spaces']
|
||||
ignore_spaces = module.params['ignore_spaces']
|
||||
allow_no_value = module.params['allow_no_value']
|
||||
modify_inactive_option = module.params['modify_inactive_option']
|
||||
create = module.params['create']
|
||||
follow = module.params['follow']
|
||||
|
||||
|
@ -500,7 +516,7 @@ def main():
|
|||
|
||||
(changed, backup_file, diff, msg) = do_ini(
|
||||
module, path, section, option, values, state, exclusive, backup,
|
||||
no_extra_spaces, ignore_spaces, create, allow_no_value, follow)
|
||||
no_extra_spaces, ignore_spaces, create, allow_no_value, modify_inactive_option, follow)
|
||||
|
||||
if not module.check_mode and os.path.exists(path):
|
||||
file_args = module.load_file_common_arguments(module.params)
|
||||
|
|
|
@ -44,3 +44,6 @@
|
|||
|
||||
- name: include tasks to test ignore_spaces
|
||||
include_tasks: tests/05-ignore_spaces.yml
|
||||
|
||||
- name: include tasks to test modify_inactive_option
|
||||
include_tasks: tests/06-modify_inactive_option.yml
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
---
|
||||
# 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
|
||||
|
||||
## testing modify_inactive_option option
|
||||
|
||||
- name: test-modify_inactive_option 1 - create test file
|
||||
copy:
|
||||
content: |
|
||||
|
||||
[section1]
|
||||
# Uncomment the line below to enable foo
|
||||
# foo = bar
|
||||
|
||||
dest: "{{ output_file }}"
|
||||
|
||||
- name: test-modify_inactive_option 1 - 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: result1
|
||||
|
||||
- name: test-modify_inactive_option 1 - read content from output file
|
||||
slurp:
|
||||
src: "{{ output_file }}"
|
||||
register: output_content
|
||||
|
||||
- name: test-modify_inactive_option 1 - set expected content and get current ini file content
|
||||
set_fact:
|
||||
expected1: |
|
||||
|
||||
[section1]
|
||||
# Uncomment the line below to enable foo
|
||||
foo = bar
|
||||
|
||||
content1: "{{ output_content.content | b64decode }}"
|
||||
|
||||
- name: test-modify_inactive_option 1 - assert 'changed' is true, content is OK and option changed
|
||||
assert:
|
||||
that:
|
||||
- result1 is changed
|
||||
- result1.msg == 'option changed'
|
||||
- content1 == expected1
|
||||
|
||||
|
||||
- name: test-modify_inactive_option 2 - create test file
|
||||
copy:
|
||||
content: |
|
||||
|
||||
[section1]
|
||||
# Uncomment the line below to enable foo
|
||||
# foo = bar
|
||||
|
||||
dest: "{{ output_file }}"
|
||||
|
||||
- name: test-modify_inactive_option 2 - set value for foo with modify_inactive_option set to false
|
||||
ini_file:
|
||||
path: "{{ output_file }}"
|
||||
section: section1
|
||||
option: foo
|
||||
value: bar
|
||||
modify_inactive_option: false
|
||||
register: result2
|
||||
|
||||
- name: test-modify_inactive_option 2 - read content from output file
|
||||
slurp:
|
||||
src: "{{ output_file }}"
|
||||
register: output_content
|
||||
|
||||
- name: test-modify_inactive_option 2 - set expected content and get current ini file content
|
||||
set_fact:
|
||||
expected2: |
|
||||
|
||||
[section1]
|
||||
foo = bar
|
||||
# Uncomment the line below to enable foo
|
||||
# foo = bar
|
||||
|
||||
content2: "{{ output_content.content | b64decode }}"
|
||||
|
||||
- name: test-modify_inactive_option 2 - assert 'changed' is true and content is OK and option added
|
||||
assert:
|
||||
that:
|
||||
- result2 is changed
|
||||
- result2.msg == 'option added'
|
||||
- content2 == expected2
|
||||
|
||||
|
||||
- name: test-modify_inactive_option 3 - remove foo=bar with modify_inactive_option set to true to ensure it doesn't have effect for removal
|
||||
ini_file:
|
||||
path: "{{ output_file }}"
|
||||
section: section1
|
||||
option: foo
|
||||
value: bar
|
||||
modify_inactive_option: true
|
||||
state: absent
|
||||
register: result3
|
||||
|
||||
- name: test-modify_inactive_option 3 - read content from output file
|
||||
slurp:
|
||||
src: "{{ output_file }}"
|
||||
register: output_content
|
||||
|
||||
- name: test-modify_inactive_option 3 - set expected content and get current ini file content
|
||||
set_fact:
|
||||
expected3: |
|
||||
|
||||
[section1]
|
||||
# Uncomment the line below to enable foo
|
||||
# foo = bar
|
||||
|
||||
content3: "{{ output_content.content | b64decode }}"
|
||||
|
||||
- name: test-modify_inactive_option 3 - assert 'changed' is true and content is OK and active option removed
|
||||
assert:
|
||||
that:
|
||||
- result3 is changed
|
||||
- result3.msg == 'option changed'
|
||||
- content3 == expected3
|
Loading…
Reference in a new issue