From 4dedb522596227c19470a80e1f401d0fdefed976 Mon Sep 17 00:00:00 2001
From: Niko Ehrenfeuchter <nikolaus.ehrenfeuchter@unibas.ch>
Date: Fri, 8 Dec 2017 12:21:58 +0100
Subject: [PATCH] Split Update-FileIfNewer() into smaller functions, validate
 parameters.

Refers to #13
---
 AutoTx/Resources/Update-AutoTxService.ps1 | 121 ++++++++++++++++------
 1 file changed, 92 insertions(+), 29 deletions(-)

diff --git a/AutoTx/Resources/Update-AutoTxService.ps1 b/AutoTx/Resources/Update-AutoTxService.ps1
index e3773a2..d574649 100644
--- a/AutoTx/Resources/Update-AutoTxService.ps1
+++ b/AutoTx/Resources/Update-AutoTxService.ps1
@@ -83,56 +83,119 @@ function Start-MyService {
 }
 
 
-function Update-FileIfNewer([string]$SourcePath, [string]$Destination) {
-    # SourcePath is expected to be a FILE (full path)
-    # Destination is expected to be a DIRECTORY (full path)
-    $SrcDir = Split-Path $SourcePath -Parent
-    $SrcFile = Split-Path $SourcePath -Leaf
-    $SrcFileNoSuffix = [io.path]::GetFileNameWithoutExtension($SrcFile)
-    $SrcFileSuffix = [io.path]::GetExtension($SrcFile)
-    $DstPath = "$($Destination)\$($SrcFile)"
-    if (-Not (Test-Path "$DstPath")) {
-        Log-Info "File not existing in destination, NOT UPDATING: $($DstPath)"
-        Return
+function Get-WriteTime([string]$FileName) {
+    try {
+        $TimeStamp = (Get-Item "$FileName").LastWriteTime
+    }
+    catch {
+        $ex = $_.Exception.Message
+        Log-Error "Error determining file age of '$($FileName)'!`n$($ex)"
+        Exit
     }
+    Return $TimeStamp
+}
 
-    $SrcWriteTime = (Get-Item "$SourcePath").LastWriteTime
-    $TgtWriteTime = (Get-Item "$DstPath").LastWriteTime
-    if (-Not ($SrcWriteTime -gt $TgtWriteTime)) {
-        Return
+
+function File-IsUpToDate([string]$ExistingFile, [string]$UpdateCandidate) {
+    # Compare write-timestamps, return $False if $UpdateCandidate is newer.
+    Write-Verbose "Comparing $($UpdateCandidate) vs. $($ExistingFile)..."
+    $CandidateTime = Get-WriteTime -FileName $UpdateCandidate
+    $ExistingTime = Get-WriteTime -FileName $ExistingFile
+    if ($CandidateTime -le $ExistingTime) {
+        Write-Verbose "File $($ExistingFile) is up-to-date."
+        Return $True
     }
-    Log-Info -Message "Found newer file at $($SourcePath), updating..."
-    Stop-MyService
+    Return $False
+}
+
 
+function Create-Backup {
+    Param (
+        [Parameter(Mandatory=$True)]
+        [ValidateScript({Test-Path -PathType Leaf $_})]
+        [String]$FileName
+
+    )
+    $FileWithoutSuffix = [io.path]::GetFileNameWithoutExtension($FileName)
+    $FileSuffix = [io.path]::GetExtension($FileName)
+    $BaseDir = Split-Path -Parent $FileName
+    
     # assemble a timestamp string like "2017-12-04T16.41.35"
     $BakTimeStamp = Get-Date -Format s | foreach {$_ -replace ":", "."}
-    $BakName = "$($SrcFileNoSuffix)_pre-$BakTimeStamp$SrcFileSuffix"
-    Log-Info "Creating backup of '$($DstPath)' to '$($BakName)'."
+    $BakName = "$($FileWithoutSuffix)_pre-$($BakTimeStamp)$($FileSuffix)"
+    Log-Info "Creating backup of '$($FileName)' as '$($BaseDir)\$($BakName)'."
     try {
-        Rename-Item "$DstPath" "$Destination\$BakName" -ErrorAction Stop
+        Rename-Item "$FileName" "$BaseDir\$BakName" -ErrorAction Stop
     }
     catch {
         $ex = $_.Exception.Message
-        Log-Error "Backing up '$($DstPath)' as '$($BakName) FAILED!`n$($ex)"
+        Log-Error "Backing up '$($FileName)' as '$($BakName) FAILED!`n$($ex)"
         Exit
     }
+}
+
+
+function Update-File {
+    # Check the given $SrcFile if a file with the same name is existing in
+    # $DstPath. If $SrcFile is newer, stop the service, create a backup of the
+    # file in $DstPath and finally copy the file from $SrcFile to $DstPath.
+    #
+    # Return $True if the file was updated, $False otherwise.
+    #
+    # WARNING: the function TERMINATES the script on any error!
+    #
+    Param (
+        [Parameter(Mandatory=$True)]
+        [ValidateScript({[IO.Path]::IsPathRooted($_)})]
+        [String]$SrcFile,
+
+        [Parameter(Mandatory=$True)]
+        [ValidateScript({(Get-Item $_).PSIsContainer})]
+        [String]$DstPath
+    )
+
+    $DstFile = "$($DstPath)\$(Split-Path -Leaf $SrcFile)"
+    if (-Not (Test-Path "$DstFile")) {
+        Log-Info "File not existing in destination, NOT UPDATING: $($DstFile)"
+        Return $False
+    }
+
+    if (File-IsUpToDate -ExistingFile $DstFile -UpdateCandidate $SrcFile) {
+        Return $False        
+    }
+
+    Log-Info "Found newer file at $($SrcFile), updating..."
+    Stop-MyService
+
     try {
-        Copy-Item -Path $SourcePath -Destination $Destination -ErrorAction Stop
-        Log-Info "Updated config file '$($DstPath)'."
+        Create-Backup -FileName $DstFile
     }
     catch {
-        $ex = $_.Exception.Message
-        Log-Error "Copying $($SourcePath) FAILED!`n$($ex)"
+        Log-Error "Backing up $($DstFile) FAILED!`n$($_.Exception.Message)"
+        Exit
+    }
+
+    try {
+        Copy-Item -Path $SrcFile -Destination $DstPath -ErrorAction Stop
+        Log-Info "Updated config file '$($DstFile)'."
+    }
+    catch {
+        Log-Error "Copying $($SrcFile) FAILED!`n$($_.Exception.Message)"
         Exit
     }
+    Return $True
 }
 
 
 function Update-Configuration {
     $NewConfig = "$($UpdateConfigPath)\configuration.xml"
     if (Test-Path -PathType Leaf $NewConfig) {
-        Update-FileIfNewer $NewConfig $InstallationPath
+        $ret = Update-File $NewConfig $InstallationPath
+    } else {
+        $ret = $False
+        Write-Verbose "No configuration file found at '$($NewConfig)'."
     }
+    Return $ret
 }
 
 
@@ -216,7 +279,7 @@ function Log-Message([string]$Type, [string]$Message, [int]$Id){
          $msg += "--- Log Message ---`n$($Message)`n--- Log Message ---`n"
          $msg += "--- Exception ---`n$($ex)`n--- Exception ---"
      }
-     Write-Host $msg
+     Write-Verbose $msg
 }
 
 
@@ -246,7 +309,7 @@ Exit-IfDirMissing $UpdateConfigPath "configuration update"
 Exit-IfDirMissing $UpdateMarkerPath "update marker"
 Exit-IfDirMissing $UpdateBinariesPath "service binaries update"
 
-Update-Configuration
-Update-ServiceBinaries
+$ConfigUpdated = Update-Configuration
+# Update-ServiceBinaries
 
 Start-MyService
-- 
GitLab