@@ -15,41 +15,100 @@ $outputDir = Join-Path $repoRoot ("Output\{0}" -f $Configuration)
1515$stampPath = Join-Path $outputDir ' BuildStamp.json'
1616$runtimeExePath = Join-Path $outputDir ' FieldWorks.exe'
1717
18- function Test-RelevantPathChanged {
18+ function Get-DebugRebuildCheckPathspecs {
1919 param (
20- [Parameter (Mandatory = $true )][string ]$Path ,
21- [Parameter (Mandatory = $true )][datetime ]$SinceUtc
20+ [Parameter (Mandatory = $true )][ValidateSet (' Package' , ' Local' )][string ]$ResolvedLcmMode
2221 )
2322
24- if (-not (Test-Path $Path )) {
25- return $false
23+ $pathspecs = @ (
24+ ' build.ps1' ,
25+ ' Directory.Build.props' ,
26+ ' Directory.Build.targets' ,
27+ ' Directory.Packages.props' ,
28+ ' FieldWorks.proj' ,
29+ ' Build' ,
30+ ' Src' ,
31+ ' Lib'
32+ )
33+
34+ if ($ResolvedLcmMode -eq ' Local' ) {
35+ $pathspecs += @ (' FieldWorks.LocalLcm.sln' , ' Localizations/LCM' )
36+ }
37+ else {
38+ $pathspecs += ' FieldWorks.sln'
2639 }
2740
28- if ((Get-Item $Path ).PSIsContainer) {
29- $excludedSegments = @ (' \.git\' , ' \.vs\' , ' \Output\' , ' \Obj\' , ' \obj\' , ' \bin\' , ' \packages\' , ' \artifacts\' )
30- foreach ($item in Get-ChildItem - Path $Path - Recurse - Force - ErrorAction SilentlyContinue) {
31- $fullPath = $item.FullName
32- $skip = $false
33- foreach ($segment in $excludedSegments ) {
34- if ($fullPath.Contains ($segment )) {
35- $skip = $true
36- break
37- }
38- }
39-
40- if ($skip ) {
41- continue
42- }
43-
44- if ($item.LastWriteTimeUtc -gt $SinceUtc ) {
45- return $true
46- }
41+ return $pathspecs | ForEach-Object { $_ -replace ' \\' , ' /' }
42+ }
43+
44+ function Invoke-Git {
45+ param (
46+ [Parameter (Mandatory = $true )][string []]$Arguments
47+ )
48+
49+ $output = & git @Arguments
50+ if ($LASTEXITCODE -ne 0 ) {
51+ throw " Git command failed: git $ ( $Arguments -join ' ' ) "
52+ }
53+
54+ return @ ($output | ForEach-Object { $_.TrimEnd () } | Where-Object { -not [string ]::IsNullOrWhiteSpace($_ ) })
55+ }
56+
57+ function Get-GitStatusForDebugRebuildCheck {
58+ param (
59+ [Parameter (Mandatory = $true )][string []]$Pathspecs
60+ )
61+
62+ return Invoke-Git - Arguments (@ (' status' , ' --porcelain=v1' , ' --untracked-files=all' , ' --' ) + $Pathspecs )
63+ }
64+
65+ function Test-GitStateRequiresDebugRebuild {
66+ param (
67+ [Parameter (Mandatory = $true )][psobject ]$Stamp ,
68+ [Parameter (Mandatory = $true )][string []]$Pathspecs
69+ )
70+
71+ # We only skip the prelaunch build when we can prove the last successful debug build
72+ # still matches the source inputs for this debug session. The proof has three parts:
73+ # 1. the stamp recorded the same debug mode inputs we are asking for now,
74+ # 2. no relevant commits have landed since the stamped HEAD, and
75+ # 3. the current relevant worktree status still matches the stamped worktree status.
76+ # If any of those checks fail, we rebuild before launching so debugging does not start
77+ # against stale binaries or symbols.
78+
79+ if (-not ($Stamp.PSObject.Properties.Name -contains ' GitHead' ) -or [string ]::IsNullOrWhiteSpace($Stamp.GitHead )) {
80+ Write-Host " Build stamp is missing Git head metadata. Rebuilding before launch..." - ForegroundColor Yellow
81+ return $true
82+ }
83+
84+ if (-not ($Stamp.PSObject.Properties.Name -contains ' RelevantDebugPathspecs' ) -or -not ($Stamp.PSObject.Properties.Name -contains ' RelevantDebugStatus' )) {
85+ Write-Host " Build stamp is missing Git-based debug metadata. Rebuilding before launch..." - ForegroundColor Yellow
86+ return $true
87+ }
88+
89+ $stampPathspecs = @ ($Stamp.RelevantDebugPathspecs )
90+ if (($stampPathspecs.Count -ne $Pathspecs.Count ) -or (@ ($stampPathspecs ) -join " `n " ) -ne ($Pathspecs -join " `n " )) {
91+ Write-Host " Build stamp inputs do not match the requested VS Code debug mode. Rebuilding..." - ForegroundColor Yellow
92+ return $true
93+ }
94+
95+ $currentHead = (Invoke-Git - Arguments @ (' rev-parse' , ' HEAD' ))[0 ]
96+ if ($currentHead -ne $Stamp.GitHead ) {
97+ $committedChanges = Invoke-Git - Arguments (@ (' diff' , ' --name-only' , " $ ( $Stamp.GitHead ) ..$currentHead " , ' --' ) + $Pathspecs )
98+ if ($committedChanges.Count -gt 0 ) {
99+ Write-Host " Detected committed changes since the last successful $Configuration debug build. Rebuilding before launch..." - ForegroundColor Yellow
100+ return $true
47101 }
102+ }
48103
49- return $false
104+ $currentStatus = Get-GitStatusForDebugRebuildCheck - Pathspecs $Pathspecs
105+ $stampStatus = @ ($Stamp.RelevantDebugStatus )
106+ if (($stampStatus.Count -ne $currentStatus.Count ) -or (($stampStatus -join " `n " ) -ne ($currentStatus -join " `n " ))) {
107+ Write-Host " Detected working tree changes since the last successful $Configuration debug build. Rebuilding before launch..." - ForegroundColor Yellow
108+ return $true
50109 }
51110
52- return ( Get-Item $Path ).LastWriteTimeUtc -gt $SinceUtc
111+ return $false
53112}
54113
55114function Invoke-DebugBuild {
@@ -80,7 +139,6 @@ if (-not (Test-Path $stampPath) -or -not (Test-Path $runtimeExePath)) {
80139}
81140
82141$stamp = Get-Content - LiteralPath $stampPath - Raw | ConvertFrom-Json
83- $stampTimeUtc = [DateTime ]::Parse($stamp.TimestampUtc ).ToUniversalTime()
84142$resolvedLcmMode = if ($LcmMode -eq ' Local' ) { ' Local' } else { ' Package' }
85143
86144$modeMatches = ($stamp.PSObject.Properties.Name -contains ' ResolvedLcmMode' ) -and ($stamp.ResolvedLcmMode -eq $resolvedLcmMode )
@@ -92,33 +150,10 @@ if (-not $modeMatches -or -not $debugTypeMatches) {
92150 exit 0
93151}
94152
95- $pathsToCheck = @ (
96- (Join-Path $repoRoot ' build.ps1' ),
97- (Join-Path $repoRoot ' Directory.Build.props' ),
98- (Join-Path $repoRoot ' Directory.Build.targets' ),
99- (Join-Path $repoRoot ' Directory.Packages.props' ),
100- (Join-Path $repoRoot ' FieldWorks.proj' ),
101- (Join-Path $repoRoot ' Build' ),
102- (Join-Path $repoRoot ' Src' ),
103- (Join-Path $repoRoot ' Lib' )
104- )
105-
106- if ($resolvedLcmMode -eq ' Local' ) {
107- $pathsToCheck += @ (
108- (Join-Path $repoRoot ' FieldWorks.LocalLcm.sln' ),
109- (Join-Path $repoRoot ' Localizations\LCM' )
110- )
111- }
112- else {
113- $pathsToCheck += (Join-Path $repoRoot ' FieldWorks.sln' )
114- }
115-
116- foreach ($pathToCheck in $pathsToCheck ) {
117- if (Test-RelevantPathChanged - Path $pathToCheck - SinceUtc $stampTimeUtc ) {
118- Write-Host " Detected changes since the last successful $Configuration debug build. Rebuilding before launch..." - ForegroundColor Yellow
119- Invoke-DebugBuild
120- exit 0
121- }
153+ $pathspecsToCheck = Get-DebugRebuildCheckPathspecs - ResolvedLcmMode $resolvedLcmMode
154+ if (Test-GitStateRequiresDebugRebuild - Stamp $stamp - Pathspecs $pathspecsToCheck ) {
155+ Invoke-DebugBuild
156+ exit 0
122157}
123158
124159Write-Host " [OK] No relevant changes since the last successful $Configuration debug build. Skipping prelaunch build." - ForegroundColor Green
0 commit comments