forked from yaegashi/ansible-role-blockinfile
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add insertafter/insertbefore options
Reference: yaegashi#2
- Loading branch information
Showing
1 changed file
with
85 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
# Ansible blockinfile module | ||
# | ||
# Licensed under GPL version 3 or later | ||
# (c) 2014 YAEGASHI Takeshi <[email protected]> | ||
# (c) 2014, 2015 YAEGASHI Takeshi <[email protected]> | ||
# (c) 2013 Evan Kaufman <[email protected]> | ||
|
||
import re | ||
|
@@ -41,6 +41,24 @@ options: | |
description: | ||
- The text to insert inside the marker lines. | ||
If it's empty string, marker lines will also be removed. | ||
insertafter: | ||
required: false | ||
default: EOF | ||
description: | ||
- If specified, the block will be inserted after the last match of | ||
specified regular expression. A special value is available; C(EOF) for | ||
inserting the block at the end of the file. If specified regular | ||
expresion has no matches, EOF will be used instead. | ||
choices: [ 'EOF', '*regex*' ] | ||
insertbefore: | ||
required: false | ||
description: | ||
- If specified, the block will be inserted before the last match of | ||
specified regular expression. A special value is available; C(BOF) for | ||
inserting the block at the beginning of the file. If specified regular | ||
expresion has no matches, the block will be inserted at the end of the | ||
file. | ||
choices: [ 'BOF', '*regex*' ] | ||
create: | ||
required: false | ||
default: "no" | ||
|
@@ -116,10 +134,13 @@ def main(): | |
dest=dict(required=True, aliases=['name', 'destfile']), | ||
marker=dict(default='# {mark} ANSIBLE MANAGED BLOCK', type='str'), | ||
content=dict(default='', type='str'), | ||
insertafter=dict(default=None), | ||
insertbefore=dict(default=None), | ||
create=dict(default='no', choices=BOOLEANS, type='bool'), | ||
backup=dict(default='no', choices=BOOLEANS, type='bool'), | ||
validate=dict(default=None, type='str'), | ||
), | ||
mutually_exclusive=[['insertbefore', 'insertafter']], | ||
add_file_common_args=True, | ||
supports_check_mode=True | ||
) | ||
|
@@ -135,35 +156,81 @@ def main(): | |
if not os.path.exists(dest): | ||
if not module.boolean(params['create']): | ||
module.fail_json(rc=257, msg='Destination %s does not exist !' % dest) | ||
contents = '' | ||
original = None | ||
lines = [] | ||
else: | ||
f = open(dest, 'rb') | ||
contents = f.read() | ||
original = f.read() | ||
f.close() | ||
lines = original.splitlines() | ||
|
||
mfunc = lambda x: re.sub(r'{mark}', x, params['marker'], 0) | ||
markers = tuple(map(mfunc, ("BEGIN", "END"))) | ||
markers_escaped = tuple(map(lambda x: re.escape(x), markers)) | ||
if params['content'] == '': | ||
repl = '' | ||
insertbefore = params['insertbefore'] | ||
insertafter = params['insertafter'] | ||
content = params['content'] | ||
marker = params['marker'] | ||
|
||
if insertbefore is None and insertafter is None: | ||
insertafter = 'EOF' | ||
|
||
if insertafter not in (None, 'EOF'): | ||
insertre = re.compile(insertafter) | ||
elif insertbefore not in (None, 'BOF'): | ||
insertre = re.compile(insertbefore) | ||
else: | ||
repl = '%s\n%s\n%s\n' % (markers[0], params['content'], markers[1]) | ||
mre = re.compile('^%s\n(.*\n)*%s\n' % markers_escaped, re.MULTILINE) | ||
result = re.subn(mre, repl, contents, 0) | ||
if result[1] == 0 and repl != '': | ||
mre = re.compile('(\n)?\Z', re.MULTILINE) | ||
result = re.subn(mre, '\n%s' % repl, contents, 0) | ||
if result[1] > 0 and contents != result[0]: | ||
msg = '%s replacements made' % result[1] | ||
changed = True | ||
insertre = None | ||
|
||
marker0 = re.sub(r'{mark}', 'BEGIN', marker, 0) | ||
marker1 = re.sub(r'{mark}', 'END', marker, 0) | ||
if content in (None, ''): | ||
contentlines = [] | ||
else: | ||
content = re.sub('', content, '', 0) | ||
contentlines = [marker0] + content.splitlines() + [marker1] | ||
|
||
n0 = n1 = None | ||
for i, line in enumerate(lines): | ||
if line.startswith(marker0): n0 = i | ||
if line.startswith(marker1): n1 = i | ||
|
||
if None in (n0, n1): | ||
n0 = None | ||
if insertre is not None: | ||
for i, line in enumerate(lines): | ||
if insertre.search(line): n0 = i | ||
if n0 is None: | ||
n0 = len(lines) | ||
elif insertafter is not None: | ||
n0 += 1 | ||
elif insertbefore is not None: | ||
n0 = 0 # insertbefore=BOF | ||
else: | ||
n0 = len(lines) # insertafter=EOF | ||
elif n0 < n1: | ||
lines[n0:n1+1] = [] | ||
else: | ||
lines[n1:n0+1] = [] | ||
n0 = n1 | ||
|
||
lines[n0:n0] = contentlines | ||
|
||
result = '\n'.join(lines)+'\n' if lines else '' | ||
if original == result: | ||
msg = '' | ||
changed = False | ||
elif original is None: | ||
msg = 'File created' | ||
changed = True | ||
elif not contentlines: | ||
msg = 'Block removed' | ||
changed = True | ||
else: | ||
msg = 'Block inserted' | ||
changed = True | ||
|
||
if changed and not module.check_mode: | ||
if module.boolean(params['backup']) and os.path.exists(dest): | ||
module.backup_local(dest) | ||
write_changes(module, result[0], dest) | ||
write_changes(module, result, dest) | ||
|
||
msg, changed = check_file_attrs(module, changed, msg) | ||
module.exit_json(changed=changed, msg=msg) | ||
|