function Copy-AlkamiReleaseManifest { <# .SYNOPSIS Copies Orb with a file manifest to track files between releases. Files that are not tracked by the manifest are left alone. DiffMove flag makes it so that unchanged files are not copied. #> [CmdletBinding()] Param ( [Parameter(Mandatory=$false)] [Alias("TempOrbPath")] [string]$srcPath = "C:\temp\deploy\orb", [Parameter(Mandatory=$false)] [Alias("OrbPath")] [string]$dstPath, [Parameter(Mandatory=$false)] [switch] $diffMove ) $logLead = (Get-LogLeadName); if([string]::IsNullOrEmpty($dstPath)) { $dstPath = (Get-OrbPath) } if($dstPath -eq $srcPath) { Write-Warning "$logLead Cannot copy Alkami release from/to the same folder. $srcPath" return } $timer = [System.Diagnostics.Stopwatch]::StartNew() $manifestPath = Join-Path $dstPath "manifest.txt" $manifestLeftoverPath = Join-Path $dstPath "manifestLeftovers.txt" $exclude = "*log4net.config" Write-Host "$logLead Discovering files to copy:" Write-Host "$logLead Note: log4net.config files are ignored!" Write-Host "$loglead Discovering files in $srcPath" $srcFiles = (Get-RelativeFileList $srcPath -exclude $exclude) $dstFiles = @(); if(Test-Path $manifestPath) { Write-Host "$loglead Loading file paths from manifest file: $manifestPath" $dstFiles = (Get-Content $manifestPath) } else { Write-Host "$logLead Release manifest not detected at $manifestPath" Write-Host "$logLead Discovering files in $dstPath" $dstFiles = (Get-RelativeFileList $dstPath -exclude $exclude) } Write-Host "`n$logLead Copying Alkami release from $srcPath to $dstPath" Write-Host "$logLead Determining files to add." $filesToAdd = (Get-SetDifference $srcFiles $dstFiles) Write-Host "$logLead Determining files to delete." $filesToDelete = (Get-SetDifference $dstFiles $srcFiles) Write-Host "$logLead Determining files to move." $filesToMove = @(); $filesToMove = (Get-SetDifference $srcFiles $filesToAdd); $filesToMove = (Get-SetDifference $filesToMove $filesToDelete) if($diffMove.isPresent) { Write-Host "$logLead DiffMove flag is present. Finding files that have not changed to avoid copies." # Only move the files that have changed by hash comparison. $newFilesToMove = @(); foreach($file in $filesToMove) { $srcFile = Join-Path $srcPath $file $dstFile = Join-Path $dstPath $file if((Get-FileHash -path $srcFile).hash -ne (Get-FileHash -path $dstFile).hash) { Write-Verbose "$logLead $srcFile hash is different than $dstFile hash." $newFilesToMove += $file } } # Reassign $filesToMove to a list of fewer files to copy. $count = $filesToMove.Count $filesToMove = $newFilesToMove $count = $count - $filesToMove.Count Write-Host "$logLead $count files don't need to be updated!" } $addCount = $filesToAdd.count; $delCount = $filesToDelete.count; $movCount = $filesToMove.count; Write-Host "`n$logLead Peforming the following actions:" Write-Host "$logLead Adding $addCount new files." Write-Host "$logLead Copying $movCount files." Write-Host "$logLead Deleting $delCount existing files.`n" $filesToCopy = $filesToAdd + $filesToMove if($filesToCopy.Count) { Write-Host "$logLead Starting file copies." $filesPerJob = 3000; $maxJobs = 8; $numFiles = $filesToCopy.Count $numJobs = [Math]::Ceiling($numFiles / $filesPerJob); Write-Host "NumJobs $numJobs" $scriptBlock = { param ($srcPath, $dstPath, $copyFiles) $VerbosePreference = 'Continue' foreach($file in $copyFiles) { $srcFile = Join-Path $srcPath $file $dstFile = Join-Path $dstPath $file if(!(Test-Path $dstFile)) { Write-Verbose "$logLead File $dstFile doesn't exist. Creating." New-Item -ItemType File -Path $dstFile -Force | Out-Null } Write-Verbose "$logLead Copying $file" Copy-Item $srcFile $dstFile -Force } } $jobs = @() for($i = 0; $i -lt $numJobs; $i++) { $start = $i * $filesPerJob $end = ($i + 1) * $filesPerJob if($start -ge $numFiles) { break; } elseif($end -gt ($numFiles - 1)) { $end = ($numFiles - 1) } $copyFiles = $filesToCopy[$start..$end] $jobs += Start-Job -ScriptBlock $scriptBlock -ArgumentList $srcPath, $dstPath, $copyFiles $running = @($jobs | Where-Object {$_.State -in ('Running','NotStarted')}) while ($running.Count -ge $maxJobs -and $running.Count -ne 0) { $finished = Wait-Job -Job $jobs -Any $running = @($jobs | Where-Object {$_.State -in ('Running','NotStarted')}) } } # Wait for all jobs in this session to complete. Get-Job | Wait-Job > $null # Receive-Job to output the logs. $jobs | ForEach-Object { $_ | Receive-Job } } else { Write-Host "$logLead No files to copy." } if($delCount) { Write-Host "$logLead Starting file deletes." foreach($file in $filesToDelete) { $dstFile = Join-Path $dstPath $file if(test-path $dstFile) { Write-Verbose "$logLead Deleting $dstFile" Remove-Item -Path $dstFile -Force } } } else { Write-Host "$logLead No files to delete." } Write-Host "`n$logLead Writing file manifest to $manifestPath" Set-Content -Force -Path $manifestPath -Value $srcFiles # Write out leftover files that survived the release. Write-Host "`n$logLead Now determining leftover files that were untouched by the release copy in $dstPath" $dstFiles = (Get-RelativeFileList $dstPath) $leftoverFiles = Get-SetDifference $dstFiles $srcFiles Write-Host "$logLead Writing leftover files to $manifestLeftoverPath" Set-Content -Force -Path $manifestLeftoverPath -Value $leftoverFiles $symlinkPath = (Join-Path $dstPath "createSymlinks.ps1") if (Test-Path $symlinkPath) { Write-Output "$logLead Running Symlink script." & $symlinkPath } else { Write-Warning ("$logLead Symlink script not found at `"$symlinkPath`"") } $timer.Stop(); Write-Host ("`n$logLead Alkami Manifest Release Copy finished in [{0}]" -f $timer.Elapsed.ToString()) }