lineinfile - properly insert line when line exists and backrefs are enabled (#63763)

Use a separate variable for the boolean test rather than having the same variable sometimes be a boolean and sometimes be a regular expression match object

Add integration tests to cover this scenario
This commit is contained in:
Sam Doran 2019-10-22 10:01:11 -04:00 committed by GitHub
parent f6c85b7380
commit 29d4d318a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 21 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- lineinfile - properly handle inserting a line when backrefs are enabled and the line already exists in the file (https://github.com/ansible/ansible/issues/63756)

View file

@ -286,7 +286,8 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
# index[0] is the line num where regexp has been found # index[0] is the line num where regexp has been found
# index[1] is the line num where insertafter/insertbefore has been found # index[1] is the line num where insertafter/insertbefore has been found
index = [-1, -1] index = [-1, -1]
m = None match = None
exact_line_match = False
b_line = to_bytes(line, errors='surrogate_or_strict') b_line = to_bytes(line, errors='surrogate_or_strict')
# The module's doc says # The module's doc says
@ -303,18 +304,17 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
match_found = bre_m.search(b_cur_line) match_found = bre_m.search(b_cur_line)
if match_found: if match_found:
index[0] = lineno index[0] = lineno
m = match_found match = match_found
if firstmatch: if firstmatch:
break break
# 2. When no match found on the previous step, # 2. When no match found on the previous step,
# parse for searching insertafter/insertbefore: # parse for searching insertafter/insertbefore:
if not m: if not match:
for lineno, b_cur_line in enumerate(b_lines): for lineno, b_cur_line in enumerate(b_lines):
match_found = b_line == b_cur_line.rstrip(b'\r\n') if b_line == b_cur_line.rstrip(b'\r\n'):
if match_found:
index[0] = lineno index[0] = lineno
m = match_found exact_line_match = True
elif bre_ins is not None and bre_ins.search(b_cur_line): elif bre_ins is not None and bre_ins.search(b_cur_line):
if insertafter: if insertafter:
@ -334,8 +334,8 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
b_linesep = to_bytes(os.linesep, errors='surrogate_or_strict') b_linesep = to_bytes(os.linesep, errors='surrogate_or_strict')
# Exact line or Regexp matched a line in the file # Exact line or Regexp matched a line in the file
if index[0] != -1: if index[0] != -1:
if backrefs: if backrefs and match:
b_new_line = m.expand(b_line) b_new_line = match.expand(b_line)
else: else:
# Don't do backref expansion if not asked. # Don't do backref expansion if not asked.
b_new_line = b_line b_new_line = b_line
@ -345,7 +345,7 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
# If no regexp was given and no line match is found anywhere in the file, # If no regexp was given and no line match is found anywhere in the file,
# insert the line appropriately if using insertbefore or insertafter # insert the line appropriately if using insertbefore or insertafter
if regexp is None and m is None: if regexp is None and match is None and not exact_line_match:
# Insert lines # Insert lines
if insertafter and insertafter != 'EOF': if insertafter and insertafter != 'EOF':

View file

@ -126,7 +126,7 @@
lineinfile: lineinfile:
dest: "{{ output_dir }}/test.txt" dest: "{{ output_dir }}/test.txt"
state: present state: present
line: "New line after line 5" line: "New line before line 5"
insertbefore: "^This is line 5$" insertbefore: "^This is line 5$"
register: result register: result
@ -144,22 +144,33 @@
- name: assert test checksum matches after the insert before the last line - name: assert test checksum matches after the insert before the last line
assert: assert:
that: that:
- "result.stat.checksum == 'e1cae425403507feea4b55bb30a74decfdd4a23e'" - "result.stat.checksum == '2e9e460ff68929e4453eb765761fd99814f6e286'"
- name: replace a line with backrefs - name: Replace a line with backrefs
lineinfile: lineinfile:
dest: "{{ output_dir }}/test.txt" dest: "{{ output_dir }}/test.txt"
state: present state: present
line: "This is line 3" line: "This is line 3"
backrefs: yes backrefs: yes
regexp: "^(REF) .* \\1$" regexp: "^(REF) .* \\1$"
register: result register: backrefs_result1
- name: Replace a line with backrefs again
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "This is line 3"
backrefs: yes
regexp: "^(REF) .* \\1$"
register: backrefs_result2
- command: cat {{ output_dir }}/test.txt
- name: assert that the line with backrefs was changed - name: assert that the line with backrefs was changed
assert: assert:
that: that:
- result is changed - backrefs_result1 is changed
- "result.msg == 'line replaced'" - backrefs_result2 is not changed
- "backrefs_result1.msg == 'line replaced'"
- name: stat the test after the backref line was replaced - name: stat the test after the backref line was replaced
stat: stat:
@ -169,7 +180,7 @@
- name: assert test checksum matches after backref line was replaced - name: assert test checksum matches after backref line was replaced
assert: assert:
that: that:
- "result.stat.checksum == '2ccdf45d20298f9eaece73b713648e5489a52444'" - "result.stat.checksum == '72f60239a735ae06e769d823f5c2b4232c634d9c'"
- name: remove the middle line - name: remove the middle line
lineinfile: lineinfile:
@ -192,7 +203,7 @@
- name: assert test checksum matches after the middle line was removed - name: assert test checksum matches after the middle line was removed
assert: assert:
that: that:
- "result.stat.checksum == 'a6ba6865547c19d4c203c38a35e728d6d1942c75'" - "result.stat.checksum == 'd4eeb07bdebab2d1cdb3ec4a3635afa2618ad4ea'"
- name: run a validation script that succeeds - name: run a validation script that succeeds
lineinfile: lineinfile:
@ -216,7 +227,7 @@
- name: assert test checksum matches after the validation succeeded - name: assert test checksum matches after the validation succeeded
assert: assert:
that: that:
- "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'" - "result.stat.checksum == 'ab56c210ea82839a54487464800fed4878cb2608'"
- name: run a validation script that fails - name: run a validation script that fails
lineinfile: lineinfile:
@ -240,7 +251,7 @@
- name: assert test checksum matches the previous after the validation failed - name: assert test checksum matches the previous after the validation failed
assert: assert:
that: that:
- "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'" - "result.stat.checksum == 'ab56c210ea82839a54487464800fed4878cb2608'"
- name: use create=yes - name: use create=yes
lineinfile: lineinfile:
@ -351,7 +362,7 @@
- name: assert test checksum matches after inserting multiple lines - name: assert test checksum matches after inserting multiple lines
assert: assert:
that: that:
- "result.stat.checksum == 'bf5b711f8f0509355aaeb9d0d61e3e82337c1365'" - "result.stat.checksum == 'fde683229429a4f05d670e6c10afc875e1d5c489'"
- name: replace a line with backrefs included in the line - name: replace a line with backrefs included in the line
lineinfile: lineinfile:
@ -376,7 +387,7 @@
- name: assert test checksum matches after backref line was replaced - name: assert test checksum matches after backref line was replaced
assert: assert:
that: that:
- "result.stat.checksum == '04b7a54d0fb233a4e26c9e625325bb4874841b3c'" - "result.stat.checksum == '981ad35c4b30b03bc3a1beedce0d1e72c491898e'"
################################################################### ###################################################################
# issue 8535 # issue 8535