Private/Invoke-FoOutputMode.ps1
|
function Get-FoCanonicalPath { param([string]$Path) if ([string]::IsNullOrWhiteSpace($Path)) { return $Path } try { if (Test-Path -LiteralPath $Path -ErrorAction Stop) { return (Get-Item -LiteralPath $Path -ErrorAction Stop).FullName } } catch { Write-Debug $_.Exception.Message } $parent = Split-Path -Parent $Path if ($parent -and (Test-Path -LiteralPath $parent)) { return Join-Path (Get-Item -LiteralPath $parent).FullName (Split-Path -Leaf $Path) } return [System.IO.Path]::GetFullPath($Path) } function Get-FoBackupRelativePath { param( [Parameter(Mandatory)] [string]$TargetPath, [string]$BaseDirectory ) $target = Get-FoCanonicalPath $TargetPath if (-not $BaseDirectory) { $BaseDirectory = [System.IO.Path]::GetPathRoot($target) } $prefix = Get-FoCanonicalPath $BaseDirectory if (-not $prefix.EndsWith([System.IO.Path]::DirectorySeparatorChar)) { $prefix += [System.IO.Path]::DirectorySeparatorChar } if ($target.StartsWith($prefix, [StringComparison]::OrdinalIgnoreCase)) { return $target.Substring($prefix.Length) } $hash = [System.BitConverter]::ToString( [System.Security.Cryptography.SHA1]::Create().ComputeHash( [System.Text.Encoding]::UTF8.GetBytes($target.ToLowerInvariant()) ) ).Replace('-', '').ToLowerInvariant() return Join-Path $hash ([System.IO.Path]::GetFileName($target)) } function Invoke-FoPromoteOptimizedFile { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$SourceFile, [Parameter(Mandatory)] [string]$TargetPath, [string]$BackupDestination ) $staging = $TargetPath + '.fo-staging' if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging -Force } $movedToBackup = $false try { Copy-Item -LiteralPath $SourceFile -Destination $staging -Force if ($BackupDestination) { $bakDir = Split-Path -Parent $BackupDestination if ($bakDir -and -not (Test-Path -LiteralPath $bakDir)) { New-Item -ItemType Directory -Path $bakDir -Force | Out-Null } if (Test-Path -LiteralPath $TargetPath) { Move-Item -LiteralPath $TargetPath -Destination $BackupDestination -Force $movedToBackup = $true } } Move-Item -LiteralPath $staging -Destination $TargetPath -Force } catch { if ($movedToBackup -and -not (Test-Path -LiteralPath $TargetPath) -and (Test-Path -LiteralPath $BackupDestination)) { Move-Item -LiteralPath $BackupDestination -Destination $TargetPath -Force } if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging -Force -ErrorAction SilentlyContinue } throw } } function Invoke-FoCopyOptimizedFile { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$SourceFile, [Parameter(Mandatory)] [string]$DestinationPath ) $staging = $DestinationPath + '.fo-staging' if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging -Force } try { Copy-Item -LiteralPath $SourceFile -Destination $staging -Force Move-Item -LiteralPath $staging -Destination $DestinationPath -Force } catch { if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging -Force -ErrorAction SilentlyContinue } if (Test-Path -LiteralPath $DestinationPath) { $destLen = (Get-Item -LiteralPath $DestinationPath).Length $srcLen = (Get-Item -LiteralPath $SourceFile).Length if ($destLen -ne $srcLen) { Remove-Item -LiteralPath $DestinationPath -Force -ErrorAction SilentlyContinue } } throw } } function Invoke-FoOutputMode { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$SourceFile, [Parameter(Mandatory)] [string]$TargetPath, [Parameter(Mandatory)] [hashtable]$Settings ) $mode = $Settings.OutputMode $target = Get-FoCanonicalPath $TargetPath $dir = Split-Path -Parent $target $result = @{ OptimizedPath = $target OriginalPath = $target BackupPath = $null } switch ($mode) { 'Replace' { Invoke-FoPromoteOptimizedFile -SourceFile $SourceFile -TargetPath $target } 'OptimizedSuffix' { $suffix = $Settings.OptimizedSuffix $base = [System.IO.Path]::GetFileNameWithoutExtension($target) $ext = [System.IO.Path]::GetExtension($target) $outPath = Join-Path $dir ($base + $suffix + $ext) Invoke-FoCopyOptimizedFile -SourceFile $SourceFile -DestinationPath $outPath $result.OptimizedPath = $outPath $result.OriginalPath = $target } 'BackupSuffix' { $bak = $target + $Settings.BackupSuffix Invoke-FoPromoteOptimizedFile -SourceFile $SourceFile -TargetPath $target -BackupDestination $bak $result.BackupPath = $bak $result.OriginalPath = $bak } 'BackupMove' { if (-not $Settings.BackupPath) { throw 'BackupMove requires BackupPath.' } $root = Get-FoCanonicalPath $Settings.BackupPath $rel = Get-FoBackupRelativePath -TargetPath $target $bakDest = Join-Path $root $rel Invoke-FoPromoteOptimizedFile -SourceFile $SourceFile -TargetPath $target -BackupDestination $bakDest $result.BackupPath = $bakDest $result.OriginalPath = $bakDest } 'TempMove' { $root = $Settings.TempBackupPath if (-not $root) { $root = Join-Path $env:TEMP 'FileOptimizer\backups' } $root = Get-FoCanonicalPath $root $rel = Get-FoBackupRelativePath -TargetPath $target $bakDest = Join-Path $root $rel Invoke-FoPromoteOptimizedFile -SourceFile $SourceFile -TargetPath $target -BackupDestination $bakDest $result.BackupPath = $bakDest $result.OriginalPath = $bakDest } default { throw "Unknown OutputMode: $mode" } } return [PSCustomObject]$result } |