diff --git a/builders/win-python-builder.psm1 b/builders/win-python-builder.psm1 index 9614764a..aa06ba5b 100644 --- a/builders/win-python-builder.psm1 +++ b/builders/win-python-builder.psm1 @@ -25,13 +25,25 @@ class WinPythonBuilder : PythonBuilder { [string] $InstallationTemplateName [string] $InstallationScriptName [string] $OutputArtifactName + [bool] $UseNuGet WinPythonBuilder( [semver] $version, [string] $architecture, [string] $platform ) : Base($version, $architecture, $platform) { - $this.InstallationTemplateName = "win-setup-template.ps1" + if ($this.IsFreeThreaded()) { + $this.UseNuGet = $true + } + else { + $this.UseNuGet = $false + } + if ($this.UseNuGet) { + $this.InstallationTemplateName = "win-nuget-template.ps1" + } + else { + $this.InstallationTemplateName = "win-setup-template.ps1" + } $this.InstallationScriptName = "setup.ps1" $this.OutputArtifactName = "python-$Version-$Platform-$Architecture.zip" } @@ -39,7 +51,7 @@ class WinPythonBuilder : PythonBuilder { [string] GetPythonExtension() { <# .SYNOPSIS - Return extension for required version of Python executable. + Return extension for required version of Python executable. #> $extension = if ($this.Version -lt "3.5" -and $this.Version -ge "2.5") { ".msi" } else { ".exe" } @@ -50,7 +62,7 @@ class WinPythonBuilder : PythonBuilder { [string] GetArchitectureExtension() { <# .SYNOPSIS - Return architecture suffix for Python executable. + Return architecture suffix for Python executable. #> $ArchitectureExtension = "" @@ -84,19 +96,39 @@ class WinPythonBuilder : PythonBuilder { return $uri } - [string] Download() { + [string] GetNuGetPackageName() { + $packageName = "python" + $arch = $this.GetHardwareArchitecture() + if ($arch -ne "x64") { + $packageName = "${packageName}${arch}" + } + if ($this.IsFreeThreaded()) { + $packageName = "${packageName}-freethreaded" + } + return $packageName + } + + [void] Download() { <# .SYNOPSIS Download Python installation executable into artifact location. #> - - $sourceUri = $this.GetSourceUri() - - Write-Host "Sources URI: $sourceUri" - $sourcesLocation = Download-File -Uri $sourceUri -OutputFolder $this.WorkFolderLocation - Write-Debug "Done; Sources location: $sourcesLocation" - - return $sourcesLocation + if ($this.UseNuGet) { + $packageName = $this.GetNuGetPackageName() + $version = $this.Version + $tempDir = Join-Path -Path $this.WorkFolderLocation -ChildPath "Temp" + $versionDir = Join-Path -Path $tempDir -ChildPath "${packageName}.${version}" + $toolsDir = Join-Path -Path $versionDir -ChildPath "tools" + Install-Package -ProviderName "NuGet" -Name $packageName -RequiredVersion $this.Version -Destination $tempDir -Confirm:$false -Force + Move-Item -Path "${toolsDir}\*" -Destination $this.WorkFolderLocation + Remove-Item -Path $tempDir -Force -Recurse + } + else { + $sourceUri = $this.GetSourceUri() + Write-Host "Sources URI: $sourceUri" + $sourcesLocation = Download-File -Uri $sourceUri -OutputFolder $this.WorkFolderLocation + Write-Debug "Done; Sources location: $sourcesLocation" + } } [void] CreateInstallationScript() { @@ -105,8 +137,13 @@ class WinPythonBuilder : PythonBuilder { Create Python artifact installation script based on specified template. #> - $sourceUri = $this.GetSourceUri() - $pythonExecName = [IO.path]::GetFileName($sourceUri.AbsoluteUri) + if ($this.UseNuGet) { + $pythonExecName = "" + } + else { + $sourceUri = $this.GetSourceUri() + $pythonExecName = [IO.path]::GetFileName($sourceUri.AbsoluteUri) + } $installationTemplateLocation = Join-Path -Path $this.InstallationTemplatesLocation -ChildPath $this.InstallationTemplateName $installationTemplateContent = Get-Content -Path $installationTemplateLocation -Raw $installationScriptLocation = New-Item -Path $this.WorkFolderLocation -Name $this.InstallationScriptName -ItemType File diff --git a/installers/win-nuget-template.ps1 b/installers/win-nuget-template.ps1 new file mode 100644 index 00000000..14d4686a --- /dev/null +++ b/installers/win-nuget-template.ps1 @@ -0,0 +1,52 @@ +[String] $Architecture = "{{__ARCHITECTURE__}}" +[String] $Version = "{{__VERSION__}}" + +$ToolcacheRoot = $env:AGENT_TOOLSDIRECTORY +if ([string]::IsNullOrEmpty($ToolcacheRoot)) { + # GitHub images don't have `AGENT_TOOLSDIRECTORY` variable + $ToolcacheRoot = $env:RUNNER_TOOL_CACHE +} +$PythonToolcachePath = Join-Path -Path $ToolcacheRoot -ChildPath "Python" +$PythonVersionPath = Join-Path -Path $PythonToolcachePath -ChildPath $Version +$PythonArchPath = Join-Path -Path $PythonVersionPath -ChildPath $Architecture + +$IsFreeThreaded = $Architecture -match "-freethreaded" + +$MajorVersion = $Version.Split('.')[0] +$MinorVersion = $Version.Split('.')[1] + +Write-Host "Check if Python hostedtoolcache folder exist..." +if (-Not (Test-Path $PythonToolcachePath)) { + Write-Host "Create Python toolcache folder" + New-Item -ItemType Directory -Path $PythonToolcachePath | Out-Null +} + +Write-Host "Check if current Python version is installed..." +if (Test-Path $PythonArchPath) { + Write-Host "Deleting $PythonArchPath..." + Remove-Item -Path $PythonArchPath -Recurse -Force + if (Test-Path -Path "$($PythonArchPath.Parent.FullName)/${Architecture}.complete") { + Remove-Item -Path "$($PythonArchPath.Parent.FullName)/${Architecture}.complete" -Force -Verbose + } +} + +Write-Host "Create Python $Version folder in $PythonToolcachePath" +New-Item -ItemType Directory -Path $PythonArchPath -Force | Out-Null + +Write-Host "Copy Python binaries to $PythonArchPath" +Copy-Item -Path ".\*" -Destination $PythonArchPath -Recurse +Remove-Item -Path "${PythonArchPath}\setup.ps1" -Force + +Write-Host "Create `python3` symlink" +New-Item -Path "$PythonArchPath\python3.exe" -ItemType SymbolicLink -Value "$PythonArchPath\python.exe" + +Write-Host "Install and upgrade Pip" +$Env:PIP_ROOT_USER_ACTION = "ignore" +$PythonExePath = Join-Path -Path $PythonArchPath -ChildPath "python.exe" +cmd.exe /c "$PythonExePath -m ensurepip && $PythonExePath -m pip install --upgrade --force-reinstall pip --no-warn-script-location" +if ($LASTEXITCODE -ne 0) { + Throw "Error happened during pip installation / upgrade" +} + +Write-Host "Create complete file" +New-Item -ItemType File -Path $PythonVersionPath -Name "$Architecture.complete" | Out-Null