Add parameters to limit replace to certain section of the file

Add parameters 'after' and 'before' to limit the replacement/remove of
lines to a certain section of the file.
This commit is contained in:
Jens Carl 2017-03-12 00:49:39 +00:00 committed by Brian Coca
parent 6ced1ad5a2
commit cd39ff9996

View file

@ -58,6 +58,22 @@ options:
- The string to replace regexp matches. May contain backreferences
that will get expanded with the regexp capture groups if the regexp
matches. If not set, matches are removed entirely.
after:
required: false
version_added: "2.3"
description:
- If specified, the line after the replace/remove will start. Can be used
in combination with C(before).
Uses Python regular expressions; see
U(http://docs.python.org/2/library/re.html).
before:
required: false
version_added: "2.3"
description:
- If specified, the line before the replace/remove will occur. Can be used
in combination with C(after).
Uses Python regular expressions; see
U(http://docs.python.org/2/library/re.html).
backup:
required: false
default: "no"
@ -88,6 +104,31 @@ EXAMPLES = r"""
replace: '\1new.host.name\2'
backup: yes
# Replace after the expression till the end of the file
- replace:
path: /etc/hosts
regexp: '(\s+)old\.host\.name(\s+.*)?$'
replace: '\1new.host.name\2'
after: 'Start after line.*'
backup: yes
# Replace before the expression till the begin of the file
- replace:
path: /etc/hosts
regexp: '(\s+)old\.host\.name(\s+.*)?$'
replace: '\1new.host.name\2'
before: 'Start before line.*'
backup: yes
# Replace between the expressions
- replace:
path: /etc/hosts
regexp: '(\s+)old\.host\.name(\s+.*)?$'
replace: '\1new.host.name\2'
after: 'Start after line.*'
before: 'Start before line.*'
backup: yes
- replace:
path: /home/jdoe/.ssh/known_hosts
regexp: '^old\.host\.name[^\n]*\n'
@ -130,6 +171,7 @@ def write_changes(module, contents, path):
if valid:
module.atomic_move(tmpfile, path, unsafe_writes=module.params['unsafe_writes'])
def check_file_attrs(module, changed, message):
file_args = module.load_file_common_arguments(module.params)
@ -142,12 +184,15 @@ def check_file_attrs(module, changed, message):
return message, changed
def main():
module = AnsibleModule(
argument_spec=dict(
path=dict(required=True, aliases=['dest', 'destfile', 'name'], type='path'),
regexp=dict(required=True),
replace=dict(default='', type='str'),
after=dict(required=False),
before=dict(required=False),
backup=dict(default=False, type='bool'),
validate=dict(default=None, type='str'),
),
@ -169,8 +214,28 @@ def main():
contents = to_text(f.read(), errors='surrogate_or_strict')
f.close()
mre = re.compile(params['regexp'], re.MULTILINE)
result = re.subn(mre, params['replace'], contents, 0)
pattern = ''
if params['after']:
pattern = '%s(.*)' % params['after']
elif params['before']:
pattern = '(.*)%s' % params['before']
elif params['after'] and params['before']:
pattern = '%s(.*?)%s' % (params['before'], params['after'])
if pattern:
section_re = re.compile(pattern, re.DOTALL)
match = re.search(section_re, contents)
if match:
section = match.group(0)
mre = re.compile(params['regexp'], re.MULTILINE)
result = re.subn(mre, params['replace'], section, 0)
if result[1] > 0 and section != result[0]:
result = (contents.replace(section, result[0]), result[1])
else:
mre = re.compile(params['regexp'], re.MULTILINE)
result = re.subn(mre, params['replace'], contents, 0)
if result[1] > 0 and contents != result[0]:
msg = '%s replacements made' % result[1]
@ -196,5 +261,6 @@ def main():
res_args['msg'], res_args['changed'] = check_file_attrs(module, changed, msg)
module.exit_json(**res_args)
if __name__ == '__main__':
main()