Private/Logic/Eigenverft.Manifested.Sandbox.Runtime.VsCode.Discovery.ps1
|
<#
Eigenverft.Manifested.Sandbox.Runtime.VsCode.Discovery #> function ConvertTo-VSCodeVersion { [CmdletBinding()] param( [string]$VersionText ) if ([string]::IsNullOrWhiteSpace($VersionText)) { return $null } $match = [regex]::Match($VersionText, '(\d+\.\d+\.\d+)') if (-not $match.Success) { return $null } return [version]$match.Groups[1].Value } function Get-VSCodeFlavor { [CmdletBinding()] param() if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) { throw 'Only Windows hosts are supported by this VS Code runtime bootstrap.' } $archHints = @($env:PROCESSOR_ARCHITECTURE, $env:PROCESSOR_ARCHITEW6432) -join ';' if ($archHints -match 'ARM64') { return 'win32-arm64' } if ([Environment]::Is64BitOperatingSystem) { return 'win32-x64' } throw 'Only 64-bit Windows targets are supported by this VS Code runtime bootstrap.' } function Get-VSCodeUpdateTarget { [CmdletBinding()] param( [string]$Flavor ) if ([string]::IsNullOrWhiteSpace($Flavor)) { $Flavor = Get-VSCodeFlavor } switch ($Flavor) { 'win32-x64' { return 'win32-x64-archive' } 'win32-arm64' { return 'win32-arm64-archive' } default { throw "Unsupported VS Code flavor '$Flavor'." } } } function Get-VSCodePersistedPackageDetails { [CmdletBinding()] param( [string]$LocalRoot = (Get-ManifestedLocalRoot) ) return (Get-ManifestedArchivePersistedPackageDetails -CommandName 'Initialize-VSCodeRuntime' -LocalRoot $LocalRoot) } function Get-ManagedVSCodeRuntimeHome { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Version, [Parameter(Mandatory = $true)] [string]$Flavor, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $layout = Get-ManifestedLayout -LocalRoot $LocalRoot return (Get-ManagedManifestedArchiveRuntimeHome -ToolsRootPath $layout.VsCodeToolsRoot -Version $Version -Flavor $Flavor) } function Test-VSCodeRuntime { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$RuntimeHome, [switch]$RequirePortableMode ) $codePath = Join-Path $RuntimeHome 'Code.exe' $codeCmd = Join-Path $RuntimeHome 'bin\code.cmd' $dataPath = Join-Path $RuntimeHome 'data' $reportedVersion = $null $productName = $null $fileDescription = $null $signatureStatus = $null $signerSubject = $null $isMicrosoftSigned = $false $portableMode = Test-Path -LiteralPath $dataPath if (-not (Test-Path -LiteralPath $RuntimeHome)) { $status = 'Missing' } elseif (-not (Test-Path -LiteralPath $codePath) -or -not (Test-Path -LiteralPath $codeCmd)) { $status = 'NeedsRepair' } else { try { $item = Get-Item -LiteralPath $codePath $productName = $item.VersionInfo.ProductName $fileDescription = $item.VersionInfo.FileDescription } catch { $productName = $null $fileDescription = $null } try { $signature = Get-AuthenticodeSignature -FilePath $codePath $signatureStatus = $signature.Status.ToString() $signerSubject = if ($signature.SignerCertificate) { $signature.SignerCertificate.Subject } else { $null } $isMicrosoftSigned = ($signature.Status -eq [System.Management.Automation.SignatureStatus]::Valid) -and ($signerSubject -match 'Microsoft Corporation') } catch { $signatureStatus = $null $signerSubject = $null $isMicrosoftSigned = $false } try { $reportedVersion = (& $codeCmd --version 2>$null | Select-Object -First 1) if (-not $reportedVersion) { $reportedVersion = (& $codePath --version 2>$null | Select-Object -First 1) } if ($reportedVersion) { $reportedVersion = $reportedVersion.ToString().Trim() } } catch { $reportedVersion = $null } $versionObject = ConvertTo-VSCodeVersion -VersionText $reportedVersion $isStableProduct = ($productName -eq 'Visual Studio Code') -or ($fileDescription -eq 'Visual Studio Code') $portableMode = Test-Path -LiteralPath $dataPath if ($RequirePortableMode -and -not $portableMode) { $status = 'NeedsRepair' } elseif (-not $versionObject -or -not $isMicrosoftSigned -or -not $isStableProduct) { $status = 'NeedsRepair' } else { $status = 'Ready' } } [pscustomobject]@{ Status = $status IsReady = ($status -eq 'Ready') RuntimeHome = $RuntimeHome CodePath = $codePath CodeCmd = $codeCmd DataPath = $dataPath PortableMode = $portableMode ReportedVersion = $reportedVersion ProductName = $productName FileDescription = $fileDescription SignatureStatus = $signatureStatus SignerSubject = $signerSubject IsMicrosoftSigned = $isMicrosoftSigned } } function Get-InstalledVSCodeRuntime { [CmdletBinding()] param( [string]$Flavor, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) if ([string]::IsNullOrWhiteSpace($Flavor)) { $Flavor = Get-VSCodeFlavor } $layout = Get-ManifestedLayout -LocalRoot $LocalRoot $entries = @() if (Test-Path -LiteralPath $layout.VsCodeToolsRoot) { $versionRoots = Get-ChildItem -LiteralPath $layout.VsCodeToolsRoot -Directory -ErrorAction SilentlyContinue | Sort-Object -Descending -Property @{ Expression = { ConvertTo-VSCodeVersion -VersionText $_.Name } } foreach ($versionRoot in $versionRoots) { $runtimeHome = Join-Path $versionRoot.FullName $Flavor if (-not (Test-Path -LiteralPath $runtimeHome)) { continue } $validation = Test-VSCodeRuntime -RuntimeHome $runtimeHome -RequirePortableMode $expectedVersion = ConvertTo-VSCodeVersion -VersionText $versionRoot.Name $reportedVersion = ConvertTo-VSCodeVersion -VersionText $validation.ReportedVersion $versionMatches = (-not $reportedVersion) -or (-not $expectedVersion) -or ($reportedVersion -eq $expectedVersion) $entries += [pscustomobject]@{ Version = $versionRoot.Name Flavor = $Flavor RuntimeHome = $runtimeHome CodePath = $validation.CodePath CodeCmd = $validation.CodeCmd Validation = $validation VersionMatches = $versionMatches IsReady = ($validation.IsReady -and $versionMatches) } } } [pscustomobject]@{ Current = ($entries | Where-Object { $_.IsReady } | Select-Object -First 1) Valid = @($entries | Where-Object { $_.IsReady }) Invalid = @($entries | Where-Object { -not $_.IsReady }) } } function Get-ManifestedVSCodeExternalPaths { [CmdletBinding()] param() $codePaths = New-Object System.Collections.Generic.List[string] $cliPaths = New-Object System.Collections.Generic.List[string] if (-not [string]::IsNullOrWhiteSpace($env:ProgramFiles)) { $runtimeHome = Join-Path $env:ProgramFiles 'Microsoft VS Code' $codePaths.Add((Join-Path $runtimeHome 'Code.exe')) | Out-Null $cliPaths.Add((Join-Path $runtimeHome 'bin\code.cmd')) | Out-Null } if (-not [string]::IsNullOrWhiteSpace($env:LOCALAPPDATA)) { $runtimeHome = Join-Path $env:LOCALAPPDATA 'Programs\Microsoft VS Code' $codePaths.Add((Join-Path $runtimeHome 'Code.exe')) | Out-Null $cliPaths.Add((Join-Path $runtimeHome 'bin\code.cmd')) | Out-Null } [pscustomobject]@{ CodePaths = @($codePaths | Select-Object -Unique) CliPaths = @($cliPaths | Select-Object -Unique) } } function Get-ManifestedVSCodeRuntimeFromCandidatePath { [CmdletBinding()] param( [string]$CandidatePath ) $resolvedCandidatePath = Get-ManifestedFullPath -Path $CandidatePath if ([string]::IsNullOrWhiteSpace($resolvedCandidatePath) -or -not (Test-Path -LiteralPath $resolvedCandidatePath)) { return $null } $leafName = Split-Path -Leaf $resolvedCandidatePath $runtimeHome = $null if ($leafName -ieq 'Code.exe') { $runtimeHome = Split-Path -Parent $resolvedCandidatePath } elseif ($leafName -ieq 'code.cmd') { $runtimeHome = Split-Path (Split-Path -Parent $resolvedCandidatePath) -Parent } else { return $null } $validation = Test-VSCodeRuntime -RuntimeHome $runtimeHome if (-not $validation.IsReady) { return $null } $versionObject = ConvertTo-VSCodeVersion -VersionText $validation.ReportedVersion if (-not $versionObject) { return $null } [pscustomobject]@{ Version = $versionObject.ToString() Flavor = $null RuntimeHome = $runtimeHome CodePath = $validation.CodePath CodeCmd = $validation.CodeCmd Validation = $validation IsReady = $true Source = 'External' Discovery = 'Path' } } function Get-SystemVSCodeRuntime { [CmdletBinding()] param( [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $layout = Get-ManifestedLayout -LocalRoot $LocalRoot $externalPaths = Get-ManifestedVSCodeExternalPaths $candidatePaths = New-Object System.Collections.Generic.List[string] $codeCmdPath = Get-ManifestedApplicationPath -CommandName 'code.cmd' -ExcludedRoots @($layout.VsCodeToolsRoot) -AdditionalPaths $externalPaths.CliPaths if (-not [string]::IsNullOrWhiteSpace($codeCmdPath)) { $candidatePaths.Add($codeCmdPath) | Out-Null } $codePath = Get-ManifestedApplicationPath -CommandName 'code' -ExcludedRoots @($layout.VsCodeToolsRoot) -AdditionalPaths (@($externalPaths.CliPaths) + @($externalPaths.CodePaths)) if (-not [string]::IsNullOrWhiteSpace($codePath)) { $candidatePaths.Add($codePath) | Out-Null } $codeExePath = Get-ManifestedApplicationPath -CommandName 'Code.exe' -ExcludedRoots @($layout.VsCodeToolsRoot) -AdditionalPaths $externalPaths.CodePaths if (-not [string]::IsNullOrWhiteSpace($codeExePath)) { $candidatePaths.Add($codeExePath) | Out-Null } foreach ($candidatePath in @($candidatePaths | Select-Object -Unique)) { $runtime = Get-ManifestedVSCodeRuntimeFromCandidatePath -CandidatePath $candidatePath if ($runtime) { return $runtime } } return $null } function Get-VSCodeRuntimeState { [CmdletBinding()] param( [string]$Flavor, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) try { if ([string]::IsNullOrWhiteSpace($Flavor)) { $Flavor = Get-VSCodeFlavor } $layout = Get-ManifestedLayout -LocalRoot $LocalRoot } catch { return [pscustomobject]@{ Status = 'Blocked' LocalRoot = $LocalRoot Layout = $null Flavor = $Flavor Channel = 'stable' CurrentVersion = $null RuntimeHome = $null RuntimeSource = $null ExecutablePath = $null CliCommandPath = $null PortableMode = $false Runtime = $null InvalidRuntimeHomes = @() Package = $null PackagePath = $null PartialPaths = @() BlockedReason = $_.Exception.Message } } $partialPaths = @(Get-ManifestedArchiveRuntimePartialPaths -CacheRootPath $layout.VsCodeCacheRoot -StagePrefix 'vscode' -LegacyRootPaths @($layout.ToolsRoot)) $installed = Get-InstalledVSCodeRuntime -Flavor $Flavor -LocalRoot $layout.LocalRoot $managedRuntime = $installed.Current $externalRuntime = $null if (-not $managedRuntime) { $externalRuntime = Get-SystemVSCodeRuntime -LocalRoot $layout.LocalRoot } $package = Get-LatestCachedVSCodeRuntimePackage -Flavor $Flavor -LocalRoot $layout.LocalRoot $runtimeSelection = Get-ManifestedArchiveRuntimeSelection -Installed $installed -ExternalRuntime $externalRuntime -Package $package -PartialPaths $partialPaths [pscustomobject]@{ Status = $runtimeSelection.Status LocalRoot = $layout.LocalRoot Layout = $layout Flavor = $Flavor Channel = 'stable' CurrentVersion = if ($runtimeSelection.CurrentRuntime) { $runtimeSelection.CurrentRuntime.Version } elseif ($package) { $package.Version } else { $null } RuntimeHome = if ($runtimeSelection.CurrentRuntime) { $runtimeSelection.CurrentRuntime.RuntimeHome } else { $null } RuntimeSource = $runtimeSelection.RuntimeSource ExecutablePath = if ($runtimeSelection.CurrentRuntime) { $runtimeSelection.CurrentRuntime.CodePath } else { $null } CliCommandPath = if ($runtimeSelection.CurrentRuntime) { $runtimeSelection.CurrentRuntime.CodeCmd } else { $null } PortableMode = if ($runtimeSelection.CurrentRuntime) { [bool]$runtimeSelection.CurrentRuntime.Validation.PortableMode } else { $false } Runtime = if ($runtimeSelection.CurrentRuntime) { $runtimeSelection.CurrentRuntime.Validation } else { $null } InvalidRuntimeHomes = $runtimeSelection.InvalidRuntimeHomes Package = $package PackagePath = if ($package) { $package.Path } else { $null } PartialPaths = $partialPaths BlockedReason = $null } } |