Skip to content

Commit

Permalink
Add insertafter/insertbefore options
Browse files Browse the repository at this point in the history
Reference: yaegashi#2
  • Loading branch information
yaegashi committed Apr 25, 2015
1 parent 5adf567 commit 32444dc
Showing 1 changed file with 85 additions and 18 deletions.
103 changes: 85 additions & 18 deletions library/blockinfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
)
Expand All @@ -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)
Expand Down

0 comments on commit 32444dc

Please sign in to comment.