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