win_lineinfile backrefs bug fix and updated examples. (#20926)

* Bug Fix for win_lineinfile and updated examples.

- changed $backrefs to a bool so it works with true/false/yes/no. This also fixes idempotency.
- Updated Docs with an example of using backrefs.

* Made suggested updates and converted two more parameters to "bool"

* Updated the Exception message

- Now contains the Windows Exception message as well as a custom message to help point in the right direction of a failed write.

* Updated Exception Handling

- Added Exception checks for Creating and removing the temporary files.
- Changed the ErrorAction on the copy tmpfile and remove tmp file to "Stop" to
  cause the exception handler to catch all errors so we can fail gracefully
  every time.
pull/21526/head
johnnysheppard-isode 8 years ago committed by Brian Coca
parent 52960ff7d0
commit 54de41309f

@ -29,11 +29,11 @@ $path= Get-Attr $params "path" $FALSE;
$regexp = Get-Attr $params "regexp" $FALSE;
$state = Get-Attr $params "state" "present";
$line = Get-Attr $params "line" $FALSE;
$backrefs = Get-Attr $params "backrefs" "no";
$backrefs = Get-Attr -obj $params -name "backrefs" -default "no" -type "bool"
$insertafter = Get-Attr $params "insertafter" $FALSE;
$insertbefore = Get-Attr $params "insertbefore" $FALSE;
$create = Get-Attr $params "create" "no";
$backup = Get-Attr $params "backup" "no";
$create = Get-Attr $params -name "create" -default "no" -type "bool";
$backup = Get-Attr $params -name "backup" -default "no" -type "bool";
$validate = Get-Attr $params "validate" $FALSE;
$encoding = Get-Attr $params "encoding" "auto";
$newline = Get-Attr $params "newline" "windows";
@ -63,30 +63,35 @@ If (Test-Path $path -pathType container) {
}
# Write lines to a file using the specified line separator and encoding,
# Write lines to a file using the specified line separator and encoding,
# performing validation if a validation command was specified.
function WriteLines($outlines, $path, $linesep, $encodingobj, $validate) {
$temppath = [System.IO.Path]::GetTempFileName();
Try {
$temppath = [System.IO.Path]::GetTempFileName();
}
Catch {
Fail-Json ("Cannot create temporary file! (" + $_.Exception.Message + ")")
}
$joined = $outlines -join $linesep;
[System.IO.File]::WriteAllText($temppath, $joined, $encodingobj);
If ($validate -ne $FALSE) {
If (!($validate -like "*%s*")) {
Fail-Json (New-Object psobject) "validate must contain %s: $validate";
}
$validate = $validate.Replace("%s", $temppath);
$validate = $validate.Replace("%s", $temppath);
$parts = [System.Collections.ArrayList] $validate.Split(" ");
$cmdname = $parts[0];
$cmdargs = $validate.Substring($cmdname.Length + 1);
$process = [Diagnostics.Process]::Start($cmdname, $cmdargs);
$process.WaitForExit();
If ($process.ExitCode -ne 0) {
[string] $output = $process.StandardOutput.ReadToEnd();
[string] $error = $process.StandardError.ReadToEnd();
@ -95,11 +100,23 @@ function WriteLines($outlines, $path, $linesep, $encodingobj, $validate) {
}
}
# Commit changes to the path
$cleanpath = $path.Replace("/", "\");
Copy-Item $temppath $cleanpath -force;
Remove-Item $temppath -force;
Try {
Copy-Item $temppath $cleanpath -force -ErrorAction Stop;
}
Catch {
Fail-Json ("Cannot write to: $cleanpath (" + $_.Exception.Message + ")")
}
Try {
Remove-Item $temppath -force -ErrorAction Stop;
}
Catch {
Fail-Json ("Cannot remove temporary file: $temppath (" + $_.Exception.Message + ")")
}
}
@ -117,14 +134,14 @@ function BackupFile($path) {
function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $backup, $backrefs, $validate, $encodingobj, $linesep) {
# Note that we have to clean up the path because ansible wants to treat / and \ as
# Note that we have to clean up the path because ansible wants to treat / and \ as
# interchangeable in windows pathnames, but .NET framework internals do not support that.
$cleanpath = $path.Replace("/", "\");
# Check if path exists. If it does not exist, either create it if create == "yes"
# was specified or fail with a reasonable error message.
If (!(Test-Path $path)) {
If ($create -eq "no") {
If (-not $create) {
Fail-Json (New-Object psobject) "Path $path does not exist !";
}
# Create new empty file, using the specified encoding to write correct BOM
@ -139,16 +156,16 @@ function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $b
Else {
$lines = [System.Collections.ArrayList] $content;
}
# Compile the regex specified, if provided
$mre = $FALSE;
If ($regexp -ne $FALSE) {
$mre = New-Object Regex $regexp, 'Compiled';
}
# Compile the regex for insertafter or insertbefore, if provided
$insre = $FALSE;
If ($insertafter -ne $FALSE -and $insertafter -ne "BOF" -and $insertafter -ne "EOF") {
$insre = New-Object Regex $insertafter, 'Compiled';
}
@ -160,7 +177,7 @@ function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $b
# index[1] is the line num where insertafter/inserbefore has been found
$index = -1, -1;
$lineno = 0;
# The latest match object and matched line
$matched_line = "";
$m = $FALSE;
@ -186,16 +203,16 @@ function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $b
}
If ($insertbefore -ne $FALSE) {
$index[1] = $lineno;
}
}
}
$lineno = $lineno + 1;
}
$changed = $FALSE;
$msg = "";
If ($index[0] -ne -1) {
If ($backrefs -ne "no") {
If ($backrefs) {
$new_line = [regex]::Replace($matched_line, $regexp, $line);
}
Else {
@ -207,7 +224,7 @@ function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $b
$changed = $TRUE;
}
}
ElseIf ($backrefs -ne "no") {
ElseIf ($backrefs) {
# No matches - no-op
}
ElseIf ($insertbefore -eq "BOF" -or $insertafter -eq "BOF") {
@ -229,10 +246,10 @@ function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $b
# Write backup file if backup == "yes"
$backuppath = "";
If ($changed -eq $TRUE -and $backup -eq "yes") {
If ($changed -eq $TRUE -and $backup -eq $TRUE) {
$backuppath = BackupFile $path;
}
# Write changes to the path if changes were made
If ($changed) {
WriteLines $lines $path $linesep $encodingobj $validate;
@ -247,7 +264,7 @@ function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $b
backup = $backuppath
encoding = $encodingstr
}
Exit-Json $result;
}
@ -262,9 +279,9 @@ function Absent($path, $regexp, $line, $backup, $validate, $encodingobj, $linese
}
# Read the dest file lines using the indicated encoding into a mutable ArrayList. Note
# that we have to clean up the path because ansible wants to treat / and \ as
# that we have to clean up the path because ansible wants to treat / and \ as
# interchangeable in windows pathnames, but .NET framework internals do not support that.
$cleanpath = $path.Replace("/", "\");
$content = [System.IO.File]::ReadAllLines($cleanpath, $encodingobj);
If ($content -eq $null) {
@ -273,7 +290,7 @@ function Absent($path, $regexp, $line, $backup, $validate, $encodingobj, $linese
Else {
$lines = [System.Collections.ArrayList] $content;
}
# Initialize message to be returned on success
$msg = "";
@ -307,10 +324,10 @@ function Absent($path, $regexp, $line, $backup, $validate, $encodingobj, $linese
# Write backup file if backup == "yes"
$backuppath = "";
If ($changed -eq $TRUE -and $backup -eq "yes") {
If ($changed -eq $TRUE -and $backup -eq $TRUE) {
$backuppath = BackupFile $path;
}
# Write changes to the path if changes were made
If ($changed) {
WriteLines $left $path $linesep $encodingobj $validate;
@ -328,7 +345,7 @@ function Absent($path, $regexp, $line, $backup, $validate, $encodingobj, $linese
found = $fcount
encoding = $encodingstr
}
Exit-Json $result;
}
@ -362,7 +379,7 @@ If ($encoding -ne "auto") {
}
# Otherwise see if we can determine the current encoding of the target file.
# If the file doesn't exist yet (create == 'yes') we use the default or
# If the file doesn't exist yet (create == 'yes') we use the default or
# explicitly specified encoding set above.
Elseif (Test-Path $path) {
@ -382,11 +399,11 @@ Elseif (Test-Path $path) {
}
# Get the first N bytes from the file, where N is the max preamble length we saw
[Byte[]]$bom = Get-Content -Encoding Byte -ReadCount $max_preamble_len -TotalCount $max_preamble_len -Path $path;
# Iterate through the sorted encodings, looking for a full match.
$found = $FALSE;
Foreach ($encoding in $sortedlist.GetValueList()) {
$preamble = $encoding.GetPreamble();
@ -411,19 +428,19 @@ Elseif (Test-Path $path) {
}
# Main dispatch - based on the value of 'state', perform argument validation and
# Main dispatch - based on the value of 'state', perform argument validation and
# call the appropriate handler function.
If ($state -eq "present") {
If ( $backrefs -ne "no" -and $regexp -eq $FALSE ) {
If ( $backrefs -and $regexp -eq $FALSE ) {
Fail-Json (New-Object psobject) "regexp= is required with backrefs=true";
}
If ($line -eq $FALSE) {
Fail-Json (New-Object psobject) "line= is required with state=present";
}
If ($insertbefore -eq $FALSE -and $insertafter -eq $FALSE) {
$insertafter = "EOF";
}
@ -436,6 +453,6 @@ Else {
If ($regexp -eq $FALSE -and $line -eq $FALSE) {
Fail-Json (New-Object psobject) "one of line= or regexp= is required with state=absent";
}
Absent $path $regexp $line $backup $validate $encodingobj $linesep;
}

@ -147,4 +147,11 @@ EXAMPLES = r'''
path: C:\temp\testfile.txt
line: Line added to file
newline: unix
# Update a line using backrefs
- win_lineinfile:
path: C:\temp\example.conf
backrefs: yes
regexp: '(^name=)'
line: '$1JohnDoe'
'''

Loading…
Cancel
Save