summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author5an7y <[email protected]>2026-04-02 15:36:34 -0700
committer5an7y <[email protected]>2026-04-02 15:36:34 -0700
commit1a672e37d6773fa8324d358d0191f4e6fce19d47 (patch)
tree22253cb82a8a02cedd7406db9314cbe7097ad870
parentc4c1704e398b8ca96bf25f519802ae86182c140f (diff)
refactor: consolidate VS detection into Resolve-BuildEnvironment
- Remove Initialize-DevShell as a separate step; VS Dev Shell setup is now fully owned by Resolve-BuildEnvironment alongside mode detection. This eliminates the ordering problem where vswhere ran unconditionally before knowing whether the environment was EWDK (which needs no VS). - Fix EWDK regression: EWDK mode now returns early before any vswhere or Dev Shell logic is invoked. - Fix Auto+WDK from plain terminal: the old isWdk guard required UCRTVersion to be set before the Dev Shell was opened, making Auto detection fail on a clean terminal. Removed the guard; the code now falls through to Dev Shell setup and validates UCRTVersion afterward. - Fix VSINSTALLDIR trailing-backslash mismatch: when the Dev Shell is already active, VSINSTALLDIR ends with '\' while vswhere installationPath does not. Added TrimEnd('\') on both sides before comparing. - Renumber Build-Samples.ps1 step comments (old Step 5 'Detect Build Environment' merged into Step 1; remaining steps renumbered). Co-authored-by: Copilot <[email protected]>
-rw-r--r--Build-Samples.ps127
-rw-r--r--BuildEnvironment.ps1169
2 files changed, 97 insertions, 99 deletions
diff --git a/Build-Samples.ps1 b/Build-Samples.ps1
index a479177b..a73a2afa 100644
--- a/Build-Samples.ps1
+++ b/Build-Samples.ps1
@@ -292,9 +292,9 @@ function Build-SingleSample {
# Step 1 - Prepare Build Environment
# =============================================================================
-$root = (Get-Location).Path
-
-$selectedVsInstall = Initialize-DevShell -ReturnToDirectory $root
+$root = (Get-Location).Path
+$buildEnv = Resolve-BuildEnvironment -RepoRoot $root -RunMode $RunMode
+$buildNumber = $buildEnv.BuildNumber
Assert-MsBuildAvailable
# =============================================================================
@@ -377,14 +377,7 @@ if ($sampleSet.Count -eq 0) {
}
# =============================================================================
-# Step 5 - Detect Build Environment
-# =============================================================================
-
-$buildEnv = Resolve-BuildEnvironment -RepoRoot $root -RunMode $RunMode -VsInstallation $selectedVsInstall
-$buildNumber = $buildEnv.BuildNumber
-
-# =============================================================================
-# Step 6 - Determine InfVerif Options
+# Step 5 - Determine InfVerif Options
# =============================================================================
#
# Samples must build cleanly, but certain InfVerif warnings are acceptable because
@@ -400,13 +393,13 @@ else {
}
# =============================================================================
-# Step 7 - Load Exclusions
+# Step 6 - Load Exclusions
# =============================================================================
$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber
# =============================================================================
-# Step 8 - Print Build Plan
+# Step 7 - Print Build Plan
# =============================================================================
$combinationsTotal = $sampleSet.Count * $Configurations.Count * $Platforms.Count
@@ -439,7 +432,7 @@ Write-Output ""
Write-Output "Building all combinations..."
# =============================================================================
-# Step 9 - Execute Parallel Builds
+# Step 8 - Execute Parallel Builds
# =============================================================================
# Shared mutable state protected by a Mutex. This is required because
@@ -587,7 +580,7 @@ $stopwatch.Stop()
Write-Host ""
# =============================================================================
-# Step 10 - Report Failures
+# Step 9 - Report Failures
# =============================================================================
Write-Output ""
@@ -626,7 +619,7 @@ if ($buildState.SporadicSet.Count -gt 0) {
}
# =============================================================================
-# Step 11 - Final Summary
+# Step 10 - Final Summary
# =============================================================================
$elapsed = $stopwatch.Elapsed
@@ -652,7 +645,7 @@ Write-Output " HTML report: $reportHtmlPath"
Write-Output "--------------------------------------------------------------------"
# =============================================================================
-# Step 12 - Generate Reports
+# Step 11 - Generate Reports
# =============================================================================
$sortedResults = $buildState.Results | Sort-Object { $_.Sample }
diff --git a/BuildEnvironment.ps1 b/BuildEnvironment.ps1
index 0b0520da..c4e3cffa 100644
--- a/BuildEnvironment.ps1
+++ b/BuildEnvironment.ps1
@@ -67,37 +67,6 @@ function Select-VsInstallation {
return $Installations[$index]
}
-function Initialize-DevShell {
- <#
- .SYNOPSIS
- Imports the Visual Studio Developer PowerShell if not already active.
- .OUTPUTS
- Returns the selected VS installation object ({ DisplayName, InstallationPath,
- WdkVsComponentVersion }), or $null if the shell was already active.
- Callers should pass the returned object to Resolve-BuildEnvironment so VS
- selection happens exactly once.
- #>
- param([string]$ReturnToDirectory)
-
- if ($env:VSCMD_VER) {
- Write-Verbose "VS Developer Shell already active (VSCMD_VER=$env:VSCMD_VER)."
- return $null
- }
-
- $vsInstall = Select-VsInstallation (Get-VsInstallationsWithWdk)
-
- $devShellDll = Join-Path $vsInstall.InstallationPath 'Common7\Tools\Microsoft.VisualStudio.DevShell.dll'
- if (-not (Test-Path $devShellDll)) {
- Write-Error "Visual Studio Developer Shell module not found at '$devShellDll'."
- exit 1
- }
-
- Import-Module $devShellDll
- Enter-VsDevShell -VsInstallPath $vsInstall.InstallationPath
- Set-Location $ReturnToDirectory
- return $vsInstall
-}
-
function Assert-MsBuildAvailable {
<#
.SYNOPSIS Verifies msbuild.exe is on PATH. Exits with error if not found.
@@ -119,20 +88,21 @@ function Assert-MsBuildAvailable {
function Resolve-BuildEnvironment {
<#
.SYNOPSIS
- Detects or resolves the active build environment and returns metadata.
+ Detects the active build environment, opens a VS Developer Shell when needed,
+ and returns metadata about the environment.
.DESCRIPTION
- When RunMode is 'Auto', checks in priority order: EWDK, NuGet, WDK.
- EWDK is checked first because $env:BuildLab is an active, explicit signal
- whereas the packages\ folder is a passive disk artifact that may linger.
- When RunMode is explicitly set to WDK/NuGet/EWDK, skips detection and uses that mode.
- Pass the VsInstallation returned by Initialize-DevShell to avoid prompting the user
- a second time when multiple VS installations are present.
+ Handles the full setup sequence in one place:
+ 1. Detect mode: EWDK → NuGet → WDK (Auto), or use the explicitly supplied RunMode.
+ 2. For NuGet / WDK: open a VS Developer Shell if one is not already active,
+ prompting the user to choose if multiple VS installations with the required
+ WDK media are found. If the shell is already active, the matching installation
+ is located via $env:VSINSTALLDIR.
+ 3. For EWDK: skip VS detection entirely ($env:BuildLab is the authoritative signal).
Returns a hashtable: Name, BuildNumber (int), NuGetVersion, WdkVsComponentVersion.
#>
param(
[string]$RepoRoot,
- [string]$RunMode = 'Auto',
- [object]$VsInstallation = $null
+ [string]$RunMode = 'Auto'
)
$result = @{
@@ -142,63 +112,98 @@ function Resolve-BuildEnvironment {
WdkVsComponentVersion = ''
}
- $effectiveMode = $RunMode
+ # -------------------------------------------------------------------------
+ # Step 1 – Detect / validate build mode
+ # -------------------------------------------------------------------------
- # --- Resolve build environment ---
- if ($effectiveMode -eq 'EWDK' -or
- ($effectiveMode -eq 'Auto' -and $env:BuildLab -match '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$')) {
- if ($effectiveMode -eq 'EWDK') {
- # Forced EWDK: require BuildLab to be set
- if ($env:BuildLab -notmatch '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$') {
- Write-Error "RunMode is 'EWDK' but the EWDK environment variable BuildLab is not set. Ensure the EWDK is mounted and the environment is initialised."
- exit 1
- }
- }
- $result.Name = "EWDK.$($Matches.branch).$($Matches.build).$($Matches.qfe)"
- $result.BuildNumber = [int]$Matches.build
- }
- elseif ($effectiveMode -eq 'NuGet' -or
- ($effectiveMode -eq 'Auto' -and (Test-Path "$RepoRoot\packages\*"))) {
- if ($effectiveMode -eq 'NuGet' -and -not (Test-Path "$RepoRoot\packages\*")) {
- Write-Error "RunMode is 'NuGet' but no packages were found under '$RepoRoot\packages\'. Ensure NuGet restore has been run."
+ # EWDK: checked first. $env:BuildLab is an active, explicit signal that
+ # disappears when you close the EWDK prompt, unlike the packages\ folder.
+ if ($RunMode -eq 'EWDK' -or
+ ($RunMode -eq 'Auto' -and $env:BuildLab -match '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$')) {
+
+ if ($RunMode -eq 'EWDK' -and
+ $env:BuildLab -notmatch '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$') {
+ Write-Error "RunMode is 'EWDK' but the EWDK environment variable BuildLab is not set. Ensure the EWDK is mounted and the environment is initialised."
exit 1
}
- $result.Name = 'NuGet'
- $wdkPackage = Get-ChildItem "$RepoRoot\packages\*WDK.x64*" -Name -ErrorAction SilentlyContinue
- $result.NuGetVersion = ([regex]'(?<=x64\.)(\d+\.){3}\d+').Match($wdkPackage).Value
- $result.BuildNumber = [int]($result.NuGetVersion.Split('.')[2])
+ # Re-run the match to populate $Matches (the Auto branch already matched above;
+ # the forced-EWDK branch needs an explicit match after the validation guard).
+ $null = $env:BuildLab -match '^(?<branch>[^.]+)\.(?<build>\d+)\.(?<qfe>[^.]+)$'
+ $result.Name = "EWDK.$($Matches.branch).$($Matches.build).$($Matches.qfe)"
+ $result.BuildNumber = [int]$Matches.build
+ $result.WdkVsComponentVersion = '(not available for EWDK builds)'
+ return $result
}
- elseif ($effectiveMode -eq 'WDK' -or
- ($effectiveMode -eq 'Auto' -and $env:UCRTVersion -match '10\.0\.(?<build>\d+)\.0')) {
- if ($effectiveMode -eq 'WDK' -and $env:UCRTVersion -notmatch '10\.0\.(?<build>\d+)\.0') {
- Write-Error "RunMode is 'WDK' but UCRTVersion ('$env:UCRTVersion') is not set or does not match the expected format. Ensure the VS Developer Shell is active."
+
+ $isNuGet = ($RunMode -eq 'NuGet') -or
+ ($RunMode -eq 'Auto' -and (Test-Path "$RepoRoot\packages\*"))
+
+ if ($RunMode -eq 'NuGet' -and -not (Test-Path "$RepoRoot\packages\*")) {
+ Write-Error "RunMode is 'NuGet' but no packages were found under '$RepoRoot\packages\'. Ensure NuGet restore has been run."
+ exit 1
+ }
+
+ # If not EWDK and not NuGet, assume WDK. VS Dev Shell setup below will validate
+ # the environment; if no VS with WDK media is found, Select-VsInstallation errors out.
+
+ # -------------------------------------------------------------------------
+ # Step 2 – Set up VS Developer Shell
+ # -------------------------------------------------------------------------
+
+ $vsInstall = $null
+
+ if (-not $env:VSCMD_VER) {
+ # Dev Shell not active – open one now.
+ $vsInstall = Select-VsInstallation (Get-VsInstallationsWithWdk)
+ $devShellDll = Join-Path $vsInstall.InstallationPath 'Common7\Tools\Microsoft.VisualStudio.DevShell.dll'
+ if (-not (Test-Path $devShellDll)) {
+ Write-Error "Visual Studio Developer Shell module not found at '$devShellDll'."
exit 1
}
- $result.Name = 'WDK'
- $result.BuildNumber = [int]$Matches.build
+ Import-Module $devShellDll
+ Enter-VsDevShell -VsInstallPath $vsInstall.InstallationPath
+ Set-Location $RepoRoot
}
else {
- Write-Output "Environment variables {"
- Get-ChildItem env:* | Sort-Object Name
- Write-Output "Environment variables }"
- Write-Error "Could not determine build environment. Ensure EWDK, WDK, or NuGet packages are configured."
- exit 1
+ Write-Verbose "VS Developer Shell already active (VSCMD_VER=$env:VSCMD_VER)."
+ # Locate the matching installation via VSINSTALLDIR so we can read its
+ # WdkVsComponentVersion without prompting the user again.
+ # Normalize trailing backslash: VSINSTALLDIR ends with '\', vswhere paths do not.
+ $normalizedVsInstallDir = $env:VSINSTALLDIR.TrimEnd('\')
+ $vsInstall = Get-VsInstallationsWithWdk |
+ Where-Object { $_.InstallationPath.TrimEnd('\') -eq $normalizedVsInstallDir } |
+ Select-Object -First 1
+ if (-not $vsInstall) {
+ Write-Error "The active Visual Studio Developer Shell ('$env:VSINSTALLDIR') does not have the required WDK media installed. Ensure the WDK Visual Studio component is installed."
+ exit 1
+ }
}
- # WDK VS component version (EWDK does not ship this metadata)
- if ($result.Name -match '^EWDK') {
- $result.WdkVsComponentVersion = '(not available for EWDK builds)'
+ # -------------------------------------------------------------------------
+ # Step 3 – Fill mode-specific fields (Dev Shell is now guaranteed active)
+ # -------------------------------------------------------------------------
+
+ if ($isNuGet) {
+ $result.Name = 'NuGet'
+ $wdkPackage = Get-ChildItem "$RepoRoot\packages\*WDK.x64*" -Name -ErrorAction SilentlyContinue
+ $result.NuGetVersion = ([regex]'(?<=x64\.)(\d+\.){3}\d+').Match($wdkPackage).Value
+ $result.BuildNumber = [int]($result.NuGetVersion.Split('.')[2])
}
else {
- # Re-use the installation selected during Initialize-DevShell if available,
- # otherwise query vswhere again (e.g. when the Dev Shell was already active).
- $vsInstall = if ($VsInstallation) { $VsInstallation } else { Select-VsInstallation (Get-VsInstallationsWithWdk) }
- if (-not $vsInstall.WdkVsComponentVersion) {
- Write-Error "Could not determine WDK component version for '$($vsInstall.DisplayName)'. Ensure the WDK Visual Studio component is installed."
+ # WDK – Dev Shell is now active, UCRTVersion must be set.
+ if ($env:UCRTVersion -notmatch '10\.0\.(?<build>\d+)\.0') {
+ Write-Error "UCRTVersion ('$env:UCRTVersion') is not set or does not match the expected format. Ensure the VS Developer Shell is active."
exit 1
}
- $result.WdkVsComponentVersion = $vsInstall.WdkVsComponentVersion
+ $result.Name = 'WDK'
+ $result.BuildNumber = [int]$Matches.build
+ }
+
+ if (-not $vsInstall.WdkVsComponentVersion) {
+ Write-Error "Could not determine WDK component version for '$($vsInstall.DisplayName)'. Ensure the WDK Visual Studio component is installed."
+ exit 1
}
+ $result.WdkVsComponentVersion = $vsInstall.WdkVsComponentVersion
return $result
}