winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

CreatePortOverlay.ps1 (10217B)


      1 # Helper functions for dealing with the port overlay
      2 
      3 $OverlayRoot = $PSScriptRoot
      4 
      5 $ErrorActionPreference = "Stop"
      6 
      7 
      8 # Gets the versions of a port available from the official registry.
      9 # This is read from the versions JSON in the main branch.
     10 # A version looks like this:
     11 #    {
     12 #      "git-tree": "9f5e160191038cbbd2470e534c43f051c80e7d44",
     13 #      "version": "2.10.19",
     14 #      "port-version": 3
     15 #    }
     16 function Get-PortVersions
     17 {
     18     param(
     19         [Parameter(Mandatory)]
     20         [string]$Port
     21     )
     22 
     23     $initial = $Port[0]
     24     $jsonUri = "https://raw.githubusercontent.com/microsoft/vcpkg/heads/master/versions/$initial-/$Port.json"
     25     $versions = (Invoke-WebRequest -Uri $jsonUri).Content | ConvertFrom-Json -Depth 5
     26     return $versions.versions
     27 }
     28 
     29 # Gets the git-tree associated with a specific version of a port.
     30 # The git-tree is a git object hash that represents the port directory
     31 # from the appropriate version of the registry.
     32 function Get-PortVersionGitTree
     33 {
     34     param(
     35         [Parameter(Mandatory)]
     36         [string]$Port,
     37         [Parameter(Mandatory)]
     38         [string]$Version,
     39         [Parameter(Mandatory)]
     40         [string]$PortVersion
     41     )
     42 
     43     $versions = Get-PortVersions $Port
     44     $versionData = $versions | Where-Object { ($_.version -eq $Version) -and ($_."port-version" -eq $portVersion) }
     45     return $versionData."git-tree"
     46 }
     47 
     48 # Fetches and parses a git-tree as a ZIP file
     49 function Get-GitTreeAsArchive
     50 {
     51     param(
     52         [Parameter(Mandatory)]
     53         [string]$GitTree
     54     )
     55 
     56     $archiveUri = "https://github.com/microsoft/vcpkg/archive/$gitTree.zip"
     57     $response = Invoke-WebRequest -Uri $archiveUri
     58     $zipStream = [System.IO.MemoryStream]::new($response.Content)
     59     $zipArchive = [System.IO.Compression.ZipArchive]::new($zipStream)
     60     return $zipArchive
     61 }
     62 
     63 # Expands an in-memory archive and writes it to disk
     64 function Expand-ArchiveFromMemory
     65 {
     66     param(
     67         [Parameter(Mandatory)]
     68         [System.IO.Compression.ZipArchive]$Archive,
     69         [Parameter(Mandatory)]
     70         [string]$Destination
     71     )
     72 
     73     # Delete existing directory
     74     if (Test-Path $Destination)
     75     {
     76         Remove-Item -Force -Recurse $Destination
     77     }
     78 
     79     # Remove length=0 to ignore the directory itself
     80     $entries = $archive.Entries | Where-Object { $_.Length -ne 0 }
     81     if (-not $entries)
     82     {
     83         throw "Archive is empty"
     84     }
     85 
     86     New-Item -Type Directory $Destination | Out-Null
     87     foreach ($entry in $entries)
     88     {
     89         $targetPath = Join-Path $Destination $entry.Name
     90         [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $targetPath)
     91     }
     92 }
     93 
     94 # Creates a copy of a port version from the official registry in this overlay
     95 function New-PortOverlay
     96 {
     97     param(
     98         [Parameter(Mandatory)]
     99         [string]$Port,
    100         [Parameter(Mandatory)]
    101         [string]$Version,
    102         [Parameter(Mandatory)]
    103         [string]$PortVersion
    104     )
    105 
    106     $gitTree = Get-PortVersionGitTree $Port $Version $PortVersion
    107     $archive = Get-GitTreeAsArchive $gitTree
    108     $portDir = Join-Path $OverlayRoot $Port
    109     Expand-ArchiveFromMemory $archive $portDir
    110 }
    111 
    112 # Gets a git patch from a GitHub commit
    113 function Get-GitHubPatch
    114 {
    115     param(
    116         [Parameter(Mandatory)]
    117         [string]$Repo,  # as user/repo
    118         [Parameter(Mandatory)]
    119         [string]$Commit
    120     )
    121 
    122     $patchUri = "https://github.com/$repo/commit/$commit.patch"
    123     $response = Invoke-WebRequest -Uri $patchUri
    124     return $response.Content
    125 }
    126 
    127 # Filters a git patch to only include files from a given directory,
    128 # and modifies the paths to make that directory the root for the patch
    129 function Select-DirectoryInPatch
    130 {
    131     param(
    132         [Parameter(Mandatory)]
    133         [string]$Patch,
    134         [Parameter(Mandatory)]
    135         [string]$Directory
    136     )
    137 
    138     # The patch starts with the commit message, author and other metadata
    139     # Then, for each modified file there is a line like
    140     #   diff --git a/the/file/path.txt b/the/file/path.txt
    141     # Followed by that files diff
    142     # We split around those lines, and select the ones with what we want
    143     $parts = $Patch -split '(?m)^(?=diff --git)'
    144 
    145     # Always keep the header/metadata
    146     $result = $parts[0]
    147 
    148     foreach ($fileDiff in $parts)
    149     {
    150         if ($fileDiff -match "^diff --git a/$Directory/.* b/$Directory/.*")
    151         {
    152             $result += $fileDiff -replace "(a|b)/$Directory/", '$1/'
    153         }
    154     }
    155 
    156     return $result
    157 }
    158 
    159 <#
    160     When updating a portfile, we look for a section that looks like this:
    161 
    162         vcpkg_from_github(
    163             OUT_SOURCE_PATH SOURCE_PATH
    164             REPO <user/repo>
    165             REF <commith hash>
    166             SHA512 <code .tar.gz hash>
    167             HEAD_REF master
    168             PATCHES
    169                 patch-1.patch
    170                 patch-2.patch
    171         )
    172 #>
    173 
    174 # Adds a patch to a portfile.cmake
    175 function Add-PatchToPortFile
    176 {
    177     param(
    178         [Parameter(Mandatory)]
    179         [string]$Port,
    180         [Parameter(Mandatory)]
    181         [string]$PatchName
    182     )
    183 
    184     # Look for the line that says "PATCHES" and add the new patch before the closing parenthesis
    185 
    186     $portFilePath = Join-Path $OverlayRoot $Port "portfile.cmake"
    187     $originalPortFile = Get-Content $portFilePath
    188 
    189     $modifiedPortFile = @()
    190     foreach ($line in $originalPortFile)
    191     {
    192         if (-not $foundParen)
    193         {
    194             if ($line.EndsWith("PATCHES"))
    195             {
    196                 $foundPatches = $true
    197             }
    198             elseif ($line -eq ")")
    199             {
    200                 $modifiedPortFile += "        $PatchName"
    201                 $foundParen = $true
    202             }
    203         }
    204 
    205         $modifiedPortFile += $line
    206     }
    207 
    208     $modifiedPortFile | Out-File $portFilePath
    209 }
    210 
    211 # Removes all patches from portfile.cmake
    212 function Remove-PortPatches
    213 {
    214     param(
    215         [Parameter(Mandatory)]
    216         [string]$Port
    217     )
    218 
    219     # Look for the line that says "PATCHES"
    220 
    221     $portFilePath = Join-Path $OverlayRoot $Port "portfile.cmake"
    222     $originalPortFile = Get-Content $portFilePath
    223 
    224     $modifiedPortFile = @()
    225     foreach ($line in $originalPortFile)
    226     {
    227         if ($line.TrimEnd().EndsWith("PATCHES"))
    228         {
    229             $foundPatches = $true
    230         }
    231         elseif ($line -eq ")")
    232         {
    233             $foundParen = $true
    234             $modifiedPortFile += $line
    235         }
    236         elseif ($foundPatches -and -not $foundParen)
    237         {
    238             # Drop line
    239         }
    240         else
    241         {
    242             $modifiedPortFile += $line
    243         }
    244     }
    245 
    246     $modifiedPortFile | Out-File $portFilePath
    247 }
    248 
    249 # Adds a patch to a port
    250 function Add-PatchToPort
    251 {
    252     param(
    253         [Parameter(Mandatory)]
    254         [string]$Port,
    255         [Parameter(Mandatory)]
    256         [string]$PatchRepo,  # as user/repo
    257         [Parameter(Mandatory)]
    258         [string]$PatchCommit,
    259         [Parameter(Mandatory)]
    260         [string]$PatchName,
    261         [string]$PatchRoot
    262     )
    263 
    264     $patch = Get-GitHubPatch -Repo $PatchRepo -Commit $PatchCommit
    265 
    266     if ($PatchRoot)
    267     {
    268         $patch = Select-DirectoryInPatch -Patch $patch -Directory $PatchRoot
    269     }
    270 
    271     $portDir = Join-Path $OverlayRoot $Port
    272     $patch | Out-File (Join-Path $portDir $PatchName)
    273 
    274     Add-PatchToPortFile -Port $Port -PatchName $PatchName
    275 }
    276 
    277 # Sets the value of an existing function parameter.
    278 # For example, REF in vcpkg_from_github
    279 function Set-ParameterInPortFile
    280 {
    281     param(
    282         [Parameter(Mandatory)]
    283         [string]$Port,
    284         [Parameter(Mandatory)]
    285         [string]$ParameterName,
    286         [Parameter(Mandatory)]
    287         [string]$CurrentValuePattern,
    288         [Parameter(Mandatory)]
    289         [string]$NewValue
    290     )
    291 
    292     $portFilePath = Join-Path $OverlayRoot $Port 'portfile.cmake'
    293     $originalPortFile = Get-Content $portFilePath
    294 
    295     # Explanation for the regex:
    296     # '(?<=)' - lookbehind without matching
    297     # '^ +'   - the parameter is only preceeded by spaces (and followed by a single space)
    298     # '(?=)'  - lookahead without matching
    299     # ' |$'   - the parameter may be the end of the line, or be followed by something else after a space (e.g. a comment)
    300     $regex = "(?<=^ +$ParameterName )$CurrentValuePattern(?= |$)"
    301 
    302     $modifiedPortFile = $originalPortFile -replace $regex, $NewValue
    303     $modifiedPortFile | Out-File $portFilePath
    304 }
    305 
    306 # Updates the source commit used for a port.
    307 # Takes the commit hash, and the hash of the archive with the code that vcpkg will download.
    308 function Update-PortSource
    309 {
    310     param(
    311         [Parameter(Mandatory)]
    312         [string]$Port,
    313         [Parameter(Mandatory)]
    314         [string]$Commit,
    315         [Parameter(Mandatory)]
    316         [string]$SourceHash,
    317         [string]$RefPattern = '[0-9a-f]{40}( #.*)?$'
    318     )
    319 
    320     # For the REF, we also delete any comments after it that may say the wrong version
    321     Set-ParameterInPortFile $Port -ParameterName 'REF' -CurrentValuePattern $RefPattern -NewValue "$Commit # Unreleased"
    322     Set-ParameterInPortFile $Port -ParameterName 'SHA512' -CurrentValuePattern '[0-9a-f]{128}' -NewValue $SourceHash
    323 }
    324 
    325 # Updates the port version by one.
    326 function Update-PortVersion
    327 {
    328     param(
    329         [Parameter(Mandatory)]
    330         [string]$Port
    331     )
    332 
    333     $portJsonPath = Join-Path $OverlayRoot $Port "vcpkg.json"
    334     $portDefinition = Get-Content $portJsonPath | ConvertFrom-Json
    335     $portDefinition."port-version" += 1
    336     $portDefinition | ConvertTo-Json -Depth 5 | Out-File $portJsonPath
    337 }
    338 
    339 New-PortOverlay cpprestsdk -Version 2.10.18 -PortVersion 4
    340 Add-PatchToPort cpprestsdk -PatchRepo 'microsoft/winget-cli' -PatchCommit '888b4ed8f4f7d25cb05a47210e083fe29348163b' -PatchName 'add-server-certificate-validation.patch' -PatchRoot 'src/cpprestsdk/cpprestsdk'
    341 
    342 New-PortOverlay detours -Version 4.0.1 -PortVersion 8
    343 Update-PortSource detours -RefPattern 'v4.0.1' -Commit '404c153ff390cb14f1787c7feeb4908c6d79b0ab' -SourceHash '1f3f26657927fa153116dce13dbfa3319ea368e6c9017f4999b6ec24d6356c335b3d5326718d3ec707b92832763ffea092088df52596f016d7ca9b8127f7033d'
    344 Remove-PortPatches detours
    345 
    346 New-PortOverlay libyaml -Version 0.2.5 -PortVersion 5
    347 Update-PortSource libyaml -Commit '840b65c40675e2d06bf40405ad3f12dec7f35923' -SourceHash 'de85560312d53a007a2ddf1fe403676bbd34620480b1ba446b8c16bb366524ba7a6ed08f6316dd783bf980d9e26603a9efc82f134eb0235917b3be1d3eb4b302'
    348 Update-PortVersion libyaml