VSCodePackageProvider.ps1
|
function Get-VSCodePackageProvider { [CmdletBinding()] param() [pscustomobject]@{ Name = 'VSCode' Platforms = @('Windows', 'Linux', 'MacOS') RequiredModules = @('Shmuelie.Utilities') RequiredCommands = @('Shmuelie.Utilities\Get-VsCodeExtension', 'Shmuelie.Utilities\Update-VsCodeExtension') OptionNames = @('Profiles') TestAvailable = { param([hashtable]$Options) $profiles = @(Get-VSCodePackageProfiles -Options $Options) if (-not (Get-Command code -CommandType Application -ListImported -ErrorAction Ignore)) { return [pscustomobject]@{ Available = $false; Reason = "Install Visual Studio Code and expose its 'code' CLI on PATH to use provider 'VSCode'." } } if ($profiles.Count -and -not (Get-Command 'Shmuelie.Utilities\Update-VsCodeExtension' -ListImported -ErrorAction Stop).Parameters.ContainsKey('Profile')) { return [pscustomobject]@{ Available = $false; Reason = "Update Shmuelie.Utilities to a version supporting Update-VsCodeExtension -Profile to use VSCode Profiles." } } [pscustomobject]@{ Available = $true; Reason = $null } } GetTargets = { param([hashtable]$Options) $profiles = @(Get-VSCodePackageProfiles -Options $Options) foreach ($profile in @($null) + $profiles) { $id = if ($null -eq $profile) { 'extensions (default profile)' } else { "extensions (profile: $profile)" } $extensions = @(Get-VSCodePackageInventory -Profile $profile) New-PackageUpdateTarget -Target $id -Data ([pscustomobject]@{ Profile = $profile PreviousExtensions = $extensions }) } } Update = { param($Target, [hashtable]$Options) Invoke-VSCodePackageCommand -Operation Update -Profile $Target.Data.Profile $extensions = @(Get-VSCodePackageInventory -Profile $Target.Data.Profile) $result = New-PackageUpdateResult -Provider VSCode -Target $Target.Target -Status Updated -Reason 'Bulk extension update completed for this profile; individual extension outcomes are not reported.' $result | Add-Member -NotePropertyName PreviousExtensions -NotePropertyValue $Target.Data.PreviousExtensions $result | Add-Member -NotePropertyName ResultingExtensions -NotePropertyValue $extensions $result } } } function Get-VSCodePackageProfiles { [CmdletBinding()] param([Parameter(Mandatory)][hashtable]$Options) if (-not $Options.ContainsKey('Profiles')) { return } $profiles = $Options.Profiles if ($profiles -isnot [string] -and $profiles -isnot [array]) { throw "VSCode option 'Profiles' must be a profile name or an array of profile names." } $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) foreach ($profile in @($profiles)) { if ($profile -isnot [string] -or [string]::IsNullOrWhiteSpace($profile) -or $profile.StartsWith('-') -or $profile -match '[<>&|%!^`"()\x00-\x1f\x7f]') { throw "Unsafe VSCode profile name. Profiles must be nonempty strings, must not start with '-', and must not contain control characters or cmd.exe metacharacters." } if ($seen.Add($profile)) { $profile } } } function Invoke-VSCodePackageCommand { [CmdletBinding()] param( [Parameter(Mandatory)][ValidateSet('Get', 'Update')][string]$Operation, [AllowNull()][string]$Profile ) $arguments = @{ ErrorAction = 'Stop' } if ($Profile) { $arguments.Profile = $Profile } $previousExitCode = Get-Variable LASTEXITCODE -Scope Global -ErrorAction Ignore $previousExitCodeValue = if ($previousExitCode) { $previousExitCode.Value } else { $null } try { # Utilities' CLI wrappers have no success output; require fresh native evidence. $global:LASTEXITCODE = $null if ($Operation -eq 'Get') { $output = @(Shmuelie.Utilities\Get-VsCodeExtension @arguments) } else { $output = @(Shmuelie.Utilities\Update-VsCodeExtension @arguments -Confirm:$false) } $exitCode = $global:LASTEXITCODE if ($null -eq $exitCode) { throw "VSCode $Operation did not report a native exit code; the outcome is unknown." } if ($exitCode -ne 0) { throw "VSCode $Operation failed with native exit code $exitCode." } if ($Operation -eq 'Get') { $output } else { foreach ($line in $output) { Write-Verbose "$line" } } } finally { if ($previousExitCode) { $global:LASTEXITCODE = $previousExitCodeValue } else { Remove-Variable LASTEXITCODE -Scope Global -ErrorAction Ignore } } } function Get-VSCodePackageInventory { [CmdletBinding()] param([AllowNull()][string]$Profile) foreach ($extension in @(Invoke-VSCodePackageCommand -Operation Get -Profile $Profile)) { if ($extension.FullId -isnot [string] -or [string]::IsNullOrWhiteSpace($extension.FullId)) { throw 'VSCode extension discovery returned an invalid extension identifier.' } [pscustomobject]@{ FullId = $extension.FullId Version = if ($extension.Version -is [string] -and -not [string]::IsNullOrWhiteSpace($extension.Version)) { $extension.Version } else { $null } } } } |