Skip to content

Commit 0c15a3b

Browse files
committed
LT-22382 - permanently fix all staged mismatched dll's.
1 parent f758bf1 commit 0c15a3b

2 files changed

Lines changed: 140 additions & 0 deletions

File tree

Build/Agent/Remove-StaleDlls.ps1

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<#
2+
.SYNOPSIS
3+
Removes staged DLLs that don't match their expected package versions.
4+
5+
.DESCRIPTION
6+
LT-22382: MSBuild's SkipUnchangedFiles uses AssemblyVersion for comparison. Some packages
7+
(like Newtonsoft.Json) keep the same AssemblyVersion across releases but change FileVersion.
8+
This causes stale DLLs to persist in the output folder even after package updates.
9+
10+
This script reads desired versions from .csproj PackageReference elements, then checks if
11+
each staged DLL's FileVersion matches the expected version. If not, the DLL is removed so
12+
the build will copy the correct one.
13+
14+
.PARAMETER OutputDir
15+
The output directory to check (e.g., Output\Debug or Output\Release).
16+
17+
.PARAMETER RepoRoot
18+
The root of the repository. Defaults to the parent of this script's folder.
19+
20+
.EXAMPLE
21+
.\Remove-StaleDlls.ps1 -OutputDir "Output\Debug"
22+
23+
.EXAMPLE
24+
.\Remove-StaleDlls.ps1 -OutputDir "Output\Release" -WhatIf
25+
#>
26+
[CmdletBinding(SupportsShouldProcess)]
27+
param(
28+
[Parameter(Mandatory)]
29+
[string]$OutputDir,
30+
31+
[string]$RepoRoot = (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent)
32+
)
33+
34+
$ErrorActionPreference = 'Stop'
35+
36+
# Resolve output path
37+
$outputPath = if ([System.IO.Path]::IsPathRooted($OutputDir)) { $OutputDir } else { Join-Path $RepoRoot $OutputDir }
38+
39+
if (-not (Test-Path $outputPath)) {
40+
Write-Verbose "Output directory does not exist: $outputPath"
41+
return
42+
}
43+
44+
# =============================================================================
45+
# Step 1: Build map of package name -> desired version from .csproj files
46+
# =============================================================================
47+
48+
Write-Verbose "Scanning .csproj files for PackageReference elements..."
49+
$desiredVersions = @{}
50+
51+
# Scan all .csproj files for PackageReference elements
52+
Get-ChildItem (Join-Path $RepoRoot "Src") -Filter "*.csproj" -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
53+
try {
54+
[xml]$csproj = Get-Content $_.FullName -Raw
55+
$csproj.SelectNodes("//PackageReference") | ForEach-Object {
56+
$id = $_.GetAttribute("Include")
57+
$version = $_.GetAttribute("Version")
58+
if ($id -and $version) {
59+
# Later entries override earlier ones (allows for project-specific overrides)
60+
$desiredVersions[$id.ToLowerInvariant()] = $version
61+
}
62+
}
63+
} catch {
64+
Write-Verbose "Could not parse $($_.FullName): $_"
65+
}
66+
}
67+
68+
# Also check packages.config for legacy references (lower priority than PackageReference)
69+
$packagesConfigPath = Join-Path $RepoRoot "Build\nuget-common\packages.config"
70+
if (Test-Path $packagesConfigPath) {
71+
try {
72+
[xml]$packagesConfig = Get-Content $packagesConfigPath -Raw
73+
$packagesConfig.SelectNodes("//package") | ForEach-Object {
74+
$id = $_.GetAttribute("id")
75+
$version = $_.GetAttribute("version")
76+
if ($id -and $version) {
77+
$key = $id.ToLowerInvariant()
78+
# Only add if not already set by PackageReference
79+
if (-not $desiredVersions.ContainsKey($key)) {
80+
$desiredVersions[$key] = $version
81+
}
82+
}
83+
}
84+
} catch {
85+
Write-Verbose "Could not parse packages.config: $_"
86+
}
87+
}
88+
89+
Write-Verbose "Found $($desiredVersions.Count) package version specifications"
90+
91+
# =============================================================================
92+
# Step 2: Check each staged DLL's FileVersion against expected package version
93+
# =============================================================================
94+
95+
$mismatchCount = 0
96+
$checkedCount = 0
97+
98+
Get-ChildItem "$outputPath\*.dll" -ErrorAction SilentlyContinue | ForEach-Object {
99+
$stagedDll = $_
100+
# Derive package name from DLL name (e.g., Newtonsoft.Json.dll -> newtonsoft.json)
101+
$packageName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name).ToLowerInvariant()
102+
103+
# Check if we have a desired version for this package
104+
$desiredVersion = $desiredVersions[$packageName]
105+
if (-not $desiredVersion) {
106+
return # Not a tracked package, skip
107+
}
108+
109+
$checkedCount++
110+
111+
# Get FileVersion from staged DLL
112+
$fileVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($stagedDll.FullName).FileVersion
113+
114+
# Normalize desired version (strip prerelease suffix like -beta0001)
115+
$normalizedDesired = $desiredVersion -replace '-.*$', ''
116+
117+
# Check if FileVersion starts with the expected version
118+
# e.g., FileVersion "13.0.4.30916" should match desired "13.0.4"
119+
if (-not $fileVersion.StartsWith("$normalizedDesired.")) {
120+
$mismatchCount++
121+
if ($PSCmdlet.ShouldProcess($stagedDll.Name, "Remove mismatched DLL (FileVersion=$fileVersion, expected=$desiredVersion.*)")) {
122+
Remove-Item $stagedDll.FullName -Force
123+
Write-Host "Removed $($stagedDll.Name) (was $fileVersion, expected $normalizedDesired.*)" -ForegroundColor Yellow
124+
}
125+
}
126+
}
127+
128+
if ($mismatchCount -eq 0) {
129+
Write-Verbose "No mismatched DLLs found (checked $checkedCount)"
130+
} else {
131+
Write-Host "Removed $mismatchCount mismatched DLL(s)" -ForegroundColor Yellow
132+
}

build.ps1

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,14 @@ try {
292292
# Clean stale per-project obj/ folders
293293
Remove-StaleObjFolders -RepoRoot $PSScriptRoot
294294

295+
# LT-22382: Remove stale DLLs that don't match their expected package versions.
296+
# MSBuild's SkipUnchangedFiles uses AssemblyVersion, missing FileVersion-only differences.
297+
$staleDllScript = Join-Path $PSScriptRoot "Build\Agent\Remove-StaleDlls.ps1"
298+
if (Test-Path $staleDllScript) {
299+
$outputDir = "Output\$Configuration"
300+
& $staleDllScript -OutputDir $outputDir -RepoRoot $PSScriptRoot -Verbose:$VerbosePreference
301+
}
302+
295303
# =============================================================================
296304
# Build Configuration
297305
# =============================================================================

0 commit comments

Comments
 (0)