diff --git a/changelogs/fragments/win_lineinfile_newlines.yaml b/changelogs/fragments/win_lineinfile_newlines.yaml new file mode 100644 index 00000000000..d6eeb0917b1 --- /dev/null +++ b/changelogs/fragments/win_lineinfile_newlines.yaml @@ -0,0 +1,2 @@ +bugfixes: +- win_lineinfile - fixed issue where \r and \n as a string was converted to newline (https://github.com/ansible/ansible/pull/35100) diff --git a/lib/ansible/modules/windows/win_lineinfile.ps1 b/lib/ansible/modules/windows/win_lineinfile.ps1 index 134bee385a4..258bded441e 100644 --- a/lib/ansible/modules/windows/win_lineinfile.ps1 +++ b/lib/ansible/modules/windows/win_lineinfile.ps1 @@ -1,25 +1,9 @@ #!powershell -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -# WANT_JSON -# POWERSHELL_COMMON - - -# Write lines to a file using the specified line separator and encoding, -# performing validation if a validation command was specified. + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#Requires -Module Ansible.ModuleUtils.Legacy + function WriteLines($outlines, $path, $linesep, $encodingobj, $validate, $check_mode) { Try { $temppath = [System.IO.Path]::GetTempFileName(); @@ -342,15 +326,6 @@ If ($newline -eq "unix") { $linesep = "`n"; } -# Fix any CR/LF literals in the line argument. PS will not recognize either backslash -# or backtick literals in the incoming string argument without this bit of black magic. -If ($line) { - $line = $line.Replace("\r", "`r"); - $line = $line.Replace("\n", "`n"); - $line = $line.Replace("``r", "`r"); - $line = $line.Replace("``n", "`n"); -} - # Figure out the proper encoding to use for reading / writing the target file. # The default encoding is UTF-8 without BOM diff --git a/lib/ansible/modules/windows/win_lineinfile.py b/lib/ansible/modules/windows/win_lineinfile.py index 686d1deeec1..4294f50c433 100644 --- a/lib/ansible/modules/windows/win_lineinfile.py +++ b/lib/ansible/modules/windows/win_lineinfile.py @@ -56,6 +56,8 @@ options: description: - Required for C(state=present). The line to insert/replace into the file. If C(backrefs) is set, may contain backreferences that will get expanded with the C(regexp) capture groups if the regexp matches. + - Be aware that the line is processed first on the controller and thus is dependent on yaml quoting rules. Any double quoted line + will have control characters, such as '\r\n', expanded. To print such characters literally, use single or no quotes. backrefs: required: false default: "no" @@ -123,6 +125,11 @@ notes: EXAMPLES = r''' # Before 2.3, option 'dest', 'destfile' or 'name' was used instead of 'path' +- name: insert path without converting \r\n + win_lineinfile: + path: c:\file.txt + line: c:\return\new + - win_lineinfile: path: C:\temp\example.conf regexp: '^name=' diff --git a/test/integration/targets/win_lineinfile/files/test_linebreak.txt b/test/integration/targets/win_lineinfile/files/test_linebreak.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/integration/targets/win_lineinfile/tasks/main.yml b/test/integration/targets/win_lineinfile/tasks/main.yml index cd995c11916..a1d9622535e 100644 --- a/test/integration/targets/win_lineinfile/tasks/main.yml +++ b/test/integration/targets/win_lineinfile/tasks/main.yml @@ -638,3 +638,66 @@ assert: that: - "result.stat.checksum == '66a72e71f42c4775f4326da95cfe82c8830e5022'" + +######################################################################### +# issue #33858 +# \r\n causes line break instead of printing literally which breaks paths. + +- name: create testing file + win_copy: + src: test_linebreak.txt + dest: "{{win_output_dir}}/test_linebreak.txt" + +- name: stat the test file + win_stat: + path: "{{win_output_dir}}/test_linebreak.txt" + register: result + +# (Get-FileHash -path C:\ansible\test\integration\targets\win_lineinfile\files\test_linebreak.txt -Algorithm sha1).hash.tolower() +- name: check win_stat file result + assert: + that: + - result.stat.exists + - not result.stat.isdir + - result.stat.checksum == 'da39a3ee5e6b4b0d3255bfef95601890afd80709' + - result is not failed + - result is not changed + +- name: insert path c:\return\new to test file + win_lineinfile: + dest: "{{win_output_dir}}/test_linebreak.txt" + line: c:\return\new + register: result_literal + +- name: insert path "c:\return\new" to test file, will cause line breaks + win_lineinfile: + dest: "{{win_output_dir}}/test_linebreak.txt" + line: "c:\return\new" + register: result_expand + +- name: assert that the lines were inserted + assert: + that: + - result_literal.changed == true + - result_literal.msg == 'line added' + - result_expand.changed == true + - result_expand.msg == 'line added' + +- name: stat the test file + win_stat: + path: "{{win_output_dir}}/test_linebreak.txt" + register: result + +- debug: + var: result + verbosity: 1 + +# expect that the file looks like this: +# c:\return\new +# c: +# eturn +# ew #or c:eturnew on windows +- name: assert that one line is literal and the other has breaks + assert: + that: + - result.stat.checksum == 'd2dfd11bc70526ff13a91153c76a7ae5595a845b'