250 lines
9.4 KiB
PowerShell
250 lines
9.4 KiB
PowerShell
function Compare-File {
|
|
<#
|
|
.SYNOPSIS
|
|
Compares two files, displaying differences in a manner similar to traditional console-based diff utilities.
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
$CompareFrom,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
$CompareTo,
|
|
[Parameter(Mandatory = $false)]
|
|
[int]$SurroundingLines = 5,
|
|
[switch]$Porcelain
|
|
)
|
|
|
|
$CompareFrom = (Resolve-Path $CompareFrom).Path
|
|
$CompareTo = (Resolve-Path $CompareTo).Path
|
|
|
|
$totalFormatWidth = 14 # 5 x2 for numbers, 4 for column separators
|
|
$screenWidth = Get-ConsoleDisplayWidth
|
|
$fixedWidth = ($screenWidth - ($screenWidth % 2) - $totalFormatWidth) / 2
|
|
$fileHeaderPrint = " "
|
|
|
|
$fileHeaderFrom = Select-RightSubstringWithPadLeft -String $CompareFrom -Length ($screenWidth - 10)
|
|
$fileHeaderTo = Select-RightSubstringWithPadLeft -String $CompareTo -Length ($screenWidth - 10)
|
|
|
|
## Get the content from each file
|
|
$contentFrom = Get-Content -Path $CompareFrom
|
|
$contentTo = Get-Content -Path $CompareTo
|
|
|
|
## Compare the two files. Get-Content annotates output objects with
|
|
## a 'ReadCount' property that represents the line number in the file
|
|
## that the text came from.
|
|
$comparedLines = Compare-Object -ReferenceObject $contentFrom -DifferenceObject $contentTo -IncludeEqual | Sort-Object { $line.InputObject.ReadCount }
|
|
|
|
if ($comparedLines.Count -eq 0) {
|
|
if (!$Porcelain) {
|
|
"$fileHeaderPrint : $fileHeaderFrom : $fileHeaderTo"
|
|
Write-Host "Contents were the same"
|
|
}
|
|
return
|
|
}
|
|
|
|
$shortestFileLength = [Math]::Max($contentFrom.Length, $contentTo.Length)
|
|
$lineNumberColor = $PSStyle.ForegroundColor.LightCyan
|
|
$reset = $PSStyle.Reset
|
|
$diffLeftColor = $PSStyle.ForegroundColor.LightRed
|
|
$diffRightColor = $PSStyle.ForegroundColor.Green
|
|
<#
|
|
$lineNumber = 0
|
|
$fromResults = @{}
|
|
$toResults = @{}
|
|
$lineNumbers = @()
|
|
foreach ($line in $comparedLines) {
|
|
$lineNumber = $line.InputObject.ReadCount
|
|
if($line.SideIndicator -eq "=>")
|
|
{
|
|
$lineNumbers += $lineNumber
|
|
$fromResults["$lineNumber"] = $line.InputObject
|
|
}
|
|
elseif($line.SideIndicator -eq "<=")
|
|
{
|
|
$lineNumbers += $lineNumber
|
|
$toResults["$lineNumber"] = $line.InputObject
|
|
} else {
|
|
$fromResults["$lineNumber"] = $line.InputObject
|
|
$toResults["$lineNumber"] = $line.InputObject
|
|
}
|
|
}
|
|
#>
|
|
|
|
$compareStart = $comparedLines[0].InputObject.ReadCount
|
|
$compareEnd = $comparedLines[-1].InputObject.ReadCount
|
|
$lineNumbers = @()
|
|
$leftLineNumber = 1
|
|
$rightLineNumber = 1
|
|
$printLines = @{}
|
|
$currentLineCounter = 1
|
|
for ($i = 1; $i -le $comparedLines.Count; $i++) {
|
|
$lines = $comparedLines.Where({$_.InputObject.ReadCount -eq $i})
|
|
if ($null -eq $lines -or $lines.Count -eq 0) {
|
|
continue
|
|
}
|
|
$leftLine = $lines.Where({$_.SideIndicator -eq '=>'})[0].InputObject
|
|
$rightLine = $lines.Where({$_.SideIndicator -eq '<='})[0].InputObject
|
|
$sameLine = $lines.Where({$_.SideIndicator -eq '=='})[0].InputObject
|
|
$printLine = @{ Line = $currentLineCounter; LeftLine = $null; RightLine = $null; LeftLineNumber = $null; RightLineNumber = $null; }
|
|
$triggerSave = $false
|
|
if ($null -ne $leftLine) {
|
|
$printLine.LeftLine = $leftLine
|
|
$printLine.LeftLineNumber = $leftLineNumber
|
|
$triggerSave = $true
|
|
$leftLineNumber += 1
|
|
}
|
|
if ($null -ne $rightLine) {
|
|
$printLine.RightLine = $rightLine
|
|
$printLine.RightLineNumber = $rightLineNumber
|
|
$triggerSave = $true
|
|
$rightLineNumber += 1
|
|
}
|
|
if ($triggerSave) {
|
|
$printLines[$currentLineCounter] = $printLine
|
|
$lineNumbers += $currentLineCounter
|
|
}
|
|
if ($null -ne $sameLine) {
|
|
$triggerSave = $true
|
|
$printLine = @{ Line = $currentLineCounter; LeftLine = $sameLine; RightLine = $sameLine; LeftLineNumber = $leftLineNumber; RightLineNumber = $rightLineNumber; }
|
|
$rightLineNumber += 1
|
|
$leftLineNumber += 1
|
|
}
|
|
if ($triggerSave) {
|
|
$printLines[$currentLineCounter] = $printLine
|
|
$currentLineCounter += 1
|
|
}
|
|
<#continue
|
|
if ($lines.Where({$_.SideIndicator -eq "=="}).Count -gt 0) {
|
|
$left["$i"] = $lines[0].InputObject
|
|
$right["$i"] = $lines[0].InputObject
|
|
}
|
|
if ($lines.Where({$_.SideIndicator -eq '=>'}).Count -gt 0) {
|
|
$left["$i"] = $lines.Where({$_.SideIndicator -eq '=>'})[0].InputObject
|
|
$lineNumbers += $i
|
|
}
|
|
if ($lines.Where({$_.SideIndicator -eq '<='}).Count -gt 0) {
|
|
$right["$i"] = $lines.Where({$_.SideIndicator -eq '<='})[0].InputObject
|
|
$lineNumbers += $i
|
|
}#>
|
|
}
|
|
|
|
if ($lineNumbers.Count -gt 0) {
|
|
$lineNumbers = $lineNumbers | Sort-Object | Get-Unique
|
|
|
|
$groups = Group-Numbers -Values $lineNumbers
|
|
<#foreach($group in $groups) {
|
|
Write-Host ($group -join ',')
|
|
}#>
|
|
$printedLineNumbers = @()
|
|
$headerBoxContent = @()
|
|
$headerBoxContent += "Left: $($fileHeaderFrom.Trim())"
|
|
$headerBoxContent += "Right: $($fileHeaderTo.Trim())"
|
|
$headerBox = Show-Box -Content $headerBoxContent -Padding 0
|
|
$print = @($headerBox)
|
|
|
|
$groupsCount = $groups.Count
|
|
$groupCounter = 1
|
|
|
|
foreach ($group in $groups) {
|
|
$first = $group[0] - $SurroundingLines
|
|
if ($first -lt 1) {
|
|
$first = 1
|
|
}
|
|
$last = $group[-1] + $SurroundingLines
|
|
if ($last -gt $shortestFileLength) {
|
|
$last = $shortestFileLength
|
|
}
|
|
for ($i = $first; $i -le $last; $i++) {
|
|
if ($printedLineNumbers -contains $i) {
|
|
continue
|
|
}
|
|
$line = $printLines[$i]
|
|
$left = $line.LeftLine
|
|
$right = $line.RightLine
|
|
if ($lineNumbers -contains $i) {
|
|
# We need to print this as a difference
|
|
$diffLeftColor = $PSStyle.ForegroundColor.LightRed
|
|
$leftLineLead = " -"
|
|
if ([string]::IsNullOrWhiteSpace($left)) {
|
|
$leftLineLead = ""
|
|
}
|
|
$diffRightColor = $PSStyle.ForegroundColor.Green
|
|
$rightLineLead = " +"
|
|
if ([string]::IsNullOrWhiteSpace($right)) {
|
|
$rightLineLead = ""
|
|
}
|
|
} else {
|
|
# This is not a difference line, print it "normally"
|
|
$diffLeftColor = $PSStyle.Reset
|
|
$diffRightColor = $PSStyle.Reset
|
|
$leftLineLead = " "
|
|
$rightLineLead = " "
|
|
}
|
|
$lineNumberLeft = "$($line.LeftLineNumber)".PadLeft(5)
|
|
$lineNumberRight = "$($line.RightLineNumber)".PadLeft(5)
|
|
$right = "$rightLineLead$right".PadRight($fixedWidth," ").Substring(0,$fixedWidth)
|
|
$left = "$leftLineLead$left".PadRight($fixedWidth," ").Substring(0,$fixedWidth)
|
|
$print += "$lineNumberColor$lineNumberLeft$reset $diffLeftColor$left$reset :$lineNumberColor$lineNumberRight$reset $diffRightColor$right$reset"
|
|
$printedLineNumbers += $i
|
|
}
|
|
if ($groupCounter -lt $groupsCount) {
|
|
if ($last -lt ($groups[$groupCounter][0] - $SurroundingLines)) {
|
|
$print += Show-Line -Style LeftHalf
|
|
}
|
|
}
|
|
$groupCounter += 1
|
|
}
|
|
|
|
if ($print.Count -gt 0) {
|
|
$print
|
|
} else {
|
|
}
|
|
} else {
|
|
if (!$Porcelain) {
|
|
"$fileHeaderPrint $fileHeaderFrom : $fileHeaderTo"
|
|
Write-Host "Contents were the same"
|
|
}
|
|
return
|
|
}
|
|
|
|
<#
|
|
$lineNumber = 0
|
|
$fromResults = @{}
|
|
$toResults = @{}
|
|
$lineNumbers = @()
|
|
foreach ($line in $comparedLines) {
|
|
$lineNumber = $line.InputObject.ReadCount
|
|
if($line.SideIndicator -eq "=>")
|
|
{
|
|
$lineNumbers += $lineNumber
|
|
$lineOperation = "added"
|
|
$fromResults[$lineNumber] = $line.InputObject
|
|
}
|
|
elseif($line.SideIndicator -eq "<=")
|
|
{
|
|
$lineNumbers += $lineNumber
|
|
$lineOperation = "deleted"
|
|
$toResults[$lineNumber] = $line.InputObject
|
|
}
|
|
}
|
|
if ($lineNumbers.Count -gt 0) {}
|
|
$lineNumbers = $lineNumbers | Sort-Object | Get-Unique
|
|
|
|
$print = @()
|
|
foreach ($lineNumber in $lineNumbers) {
|
|
$lineNumberLead = "$lineNumber".PadLeft(5, ' ')
|
|
$from = $fromResults[$lineNumber]
|
|
$from = "$from".PadRight($fixedWidth," ").Substring(0,$fixedWidth)
|
|
$to = $toResults[$lineNumber]
|
|
$to = "$to".PadRight($fixedWidth," ").Substring(0,$fixedWidth)
|
|
$print += "$($PSStyle.ForegroundColor.LightCyan)$lineNumberLead$($PSStyle.Reset) : $($PSStyle.ForegroundColor.LightRed)$from$($PSStyle.Reset) : $($PSStyle.ForegroundColor.Green)$to$($PSStyle.Reset)"
|
|
}
|
|
|
|
if ($print.Count -gt 0) {
|
|
"$fileHeaderPrint : $fileHeaderFrom : $fileHeaderTo"
|
|
$print
|
|
} else {
|
|
}
|
|
#>
|
|
} |