Skip to content

Commit

Permalink
Account for empty string regexp in lineinfile (ansible#41451)
Browse files Browse the repository at this point in the history
* Use context managers for interacting with files

* Account for empty string as regexp

Rather than explicitly testing for None, also test for an empty string which will evaluate to False. An empty string regexp matches every line, which ends up replacing the incorrect line.

* Store line parameter in a variable

* Add tests
  • Loading branch information
samdoran authored Jun 25, 2018
1 parent 3d78dd6 commit 4b5b4a7
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 17 deletions.
33 changes: 16 additions & 17 deletions lib/ansible/modules/files/lineinfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,8 @@
def write_changes(module, b_lines, dest):

tmpfd, tmpfile = tempfile.mkstemp()
f = os.fdopen(tmpfd, 'wb')
f.writelines(b_lines)
f.close()
with open(tmpfile, 'wb') as f:
f.writelines(b_lines)

validate = module.params.get('validate', None)
valid = not validate
Expand Down Expand Up @@ -247,14 +246,13 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,

b_lines = []
else:
f = open(b_dest, 'rb')
b_lines = f.readlines()
f.close()
with open(b_dest, 'rb') as f:
b_lines = f.readlines()

if module._diff:
diff['before'] = to_native(b('').join(b_lines))

if regexp is not None:
if regexp:
bre_m = re.compile(to_bytes(regexp, errors='surrogate_or_strict'))

if insertafter not in (None, 'BOF', 'EOF'):
Expand All @@ -270,7 +268,7 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
m = None
b_line = to_bytes(line, errors='surrogate_or_strict')
for lineno, b_cur_line in enumerate(b_lines):
if regexp is not None:
if regexp:
match_found = bre_m.search(b_cur_line)
else:
match_found = b_line == b_cur_line.rstrip(b('\r\n'))
Expand Down Expand Up @@ -406,21 +404,20 @@ def absent(module, dest, regexp, line, backup):
'before_header': '%s (content)' % dest,
'after_header': '%s (content)' % dest}

f = open(b_dest, 'rb')
b_lines = f.readlines()
f.close()
with open(b_dest, 'rb') as f:
b_lines = f.readlines()

if module._diff:
diff['before'] = to_native(b('').join(b_lines))

if regexp is not None:
if regexp:
bre_c = re.compile(to_bytes(regexp, errors='surrogate_or_strict'))
found = []

b_line = to_bytes(line, errors='surrogate_or_strict')

def matcher(b_cur_line):
if regexp is not None:
if regexp:
match_found = bre_c.search(b_cur_line)
else:
match_found = b_line == b_cur_line.rstrip(b('\r\n'))
Expand Down Expand Up @@ -480,13 +477,15 @@ def main():
backrefs = params['backrefs']
path = params['path']
firstmatch = params['firstmatch']
regexp = params['regexp']
line = params.get('line', None)

b_path = to_bytes(path, errors='surrogate_or_strict')
if os.path.isdir(b_path):
module.fail_json(rc=256, msg='Path %s is a directory !' % path)

if params['state'] == 'present':
if backrefs and params['regexp'] is None:
if backrefs and not regexp:
module.fail_json(msg='regexp= is required with backrefs=true')

if params.get('line', None) is None:
Expand All @@ -500,13 +499,13 @@ def main():

line = params['line']

present(module, path, params['regexp'], line,
present(module, path, regexp, line,
ins_aft, ins_bef, create, backup, backrefs, firstmatch)
else:
if params['regexp'] is None and params.get('line', None) is None:
if not regexp and line is None:
module.fail_json(msg='one of line= or regexp= is required with state=absent')

absent(module, path, params['regexp'], params.get('line', None), backup)
absent(module, path, regexp, line, backup)


if __name__ == '__main__':
Expand Down
34 changes: 34 additions & 0 deletions test/integration/targets/lineinfile/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -717,3 +717,37 @@
assert:
that:
- result.stat.checksum == 'eca8d8ea089d4ea57a3b87d4091599ca8b60dfd2'

###################################################################
# Issue 29443

- name: Deploy the test file for lineinfile
copy:
src: test.txt
dest: "{{ output_dir }}/test.txt"
register: result

- name: Assert that the test file was deployed
assert:
that:
- result is changed
- result.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'
- result.state == 'file'

- name: Insert a line in the file using an empty string as a regular expression
lineinfile:
path: "{{ output_dir }}/test.txt"
regexp: ''
line: This is line 6
register: insert_empty_regexp

- name: Stat the file
stat:
path: "{{ output_dir }}/test.txt"
register: result

- name: Assert that the file contents match what is expected
assert:
that:
- insert_empty_regexp is changed
- result.stat.checksum == '3baeade8eb2ecf4b01d70d541e9b8258b67c7f9f'

0 comments on commit 4b5b4a7

Please sign in to comment.