From 96d304a89466cae6d6afa8e3473c52efa759bcfa Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 22 Oct 2019 10:01:11 -0400 Subject: [PATCH] [temporary-2.9.1-branch-releng-only] 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 (cherry picked from commit 29d4d318a5) Co-authored-by: Sam Doran --- ...lineinfile-backrefs-match-object-type.yaml | 2 ++ lib/ansible/modules/files/lineinfile.py | 18 +++++----- .../targets/lineinfile/tasks/main.yml | 35 ++++++++++++------- 3 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 changelogs/fragments/lineinfile-backrefs-match-object-type.yaml diff --git a/changelogs/fragments/lineinfile-backrefs-match-object-type.yaml b/changelogs/fragments/lineinfile-backrefs-match-object-type.yaml new file mode 100644 index 0000000000..55d532b356 --- /dev/null +++ b/changelogs/fragments/lineinfile-backrefs-match-object-type.yaml @@ -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) diff --git a/lib/ansible/modules/files/lineinfile.py b/lib/ansible/modules/files/lineinfile.py index 6647b28e22..14d53aee13 100644 --- a/lib/ansible/modules/files/lineinfile.py +++ b/lib/ansible/modules/files/lineinfile.py @@ -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[1] is the line num where insertafter/insertbefore has been found index = [-1, -1] - m = None + match = None + exact_line_match = False b_line = to_bytes(line, errors='surrogate_or_strict') # 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) if match_found: index[0] = lineno - m = match_found + match = match_found if firstmatch: break # 2. When no match found on the previous step, # parse for searching insertafter/insertbefore: - if not m: + if not match: for lineno, b_cur_line in enumerate(b_lines): - match_found = b_line == b_cur_line.rstrip(b'\r\n') - if match_found: + if b_line == b_cur_line.rstrip(b'\r\n'): index[0] = lineno - m = match_found + exact_line_match = True elif bre_ins is not None and bre_ins.search(b_cur_line): 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') # Exact line or Regexp matched a line in the file if index[0] != -1: - if backrefs: - b_new_line = m.expand(b_line) + if backrefs and match: + b_new_line = match.expand(b_line) else: # Don't do backref expansion if not asked. 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, # 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 if insertafter and insertafter != 'EOF': diff --git a/test/integration/targets/lineinfile/tasks/main.yml b/test/integration/targets/lineinfile/tasks/main.yml index 3ede5ded6b..ec6e59e264 100644 --- a/test/integration/targets/lineinfile/tasks/main.yml +++ b/test/integration/targets/lineinfile/tasks/main.yml @@ -126,7 +126,7 @@ lineinfile: dest: "{{ output_dir }}/test.txt" state: present - line: "New line after line 5" + line: "New line before line 5" insertbefore: "^This is line 5$" register: result @@ -144,22 +144,33 @@ - name: assert test checksum matches after the insert before the last line assert: that: - - "result.stat.checksum == 'e1cae425403507feea4b55bb30a74decfdd4a23e'" + - "result.stat.checksum == '2e9e460ff68929e4453eb765761fd99814f6e286'" -- name: replace a line with backrefs +- name: Replace a line with backrefs lineinfile: dest: "{{ output_dir }}/test.txt" state: present line: "This is line 3" backrefs: yes 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 assert: that: - - result is changed - - "result.msg == 'line replaced'" + - backrefs_result1 is changed + - backrefs_result2 is not changed + - "backrefs_result1.msg == 'line replaced'" - name: stat the test after the backref line was replaced stat: @@ -169,7 +180,7 @@ - name: assert test checksum matches after backref line was replaced assert: that: - - "result.stat.checksum == '2ccdf45d20298f9eaece73b713648e5489a52444'" + - "result.stat.checksum == '72f60239a735ae06e769d823f5c2b4232c634d9c'" - name: remove the middle line lineinfile: @@ -192,7 +203,7 @@ - name: assert test checksum matches after the middle line was removed assert: that: - - "result.stat.checksum == 'a6ba6865547c19d4c203c38a35e728d6d1942c75'" + - "result.stat.checksum == 'd4eeb07bdebab2d1cdb3ec4a3635afa2618ad4ea'" - name: run a validation script that succeeds lineinfile: @@ -216,7 +227,7 @@ - name: assert test checksum matches after the validation succeeded assert: that: - - "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'" + - "result.stat.checksum == 'ab56c210ea82839a54487464800fed4878cb2608'" - name: run a validation script that fails lineinfile: @@ -240,7 +251,7 @@ - name: assert test checksum matches the previous after the validation failed assert: that: - - "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'" + - "result.stat.checksum == 'ab56c210ea82839a54487464800fed4878cb2608'" - name: use create=yes lineinfile: @@ -351,7 +362,7 @@ - name: assert test checksum matches after inserting multiple lines assert: that: - - "result.stat.checksum == 'bf5b711f8f0509355aaeb9d0d61e3e82337c1365'" + - "result.stat.checksum == 'fde683229429a4f05d670e6c10afc875e1d5c489'" - name: replace a line with backrefs included in the line lineinfile: @@ -376,7 +387,7 @@ - name: assert test checksum matches after backref line was replaced assert: that: - - "result.stat.checksum == '04b7a54d0fb233a4e26c9e625325bb4874841b3c'" + - "result.stat.checksum == '981ad35c4b30b03bc3a1beedce0d1e72c491898e'" ################################################################### # issue 8535