|
| 1 | +#ps1 |
| 2 | +param( |
| 3 | + [string]$CloudbaseInitRepoUrl="https://github.com/cloudbase/cloudbase-init", |
| 4 | + [string]$PyWin32RepoUrl="https://github.com/mhammond/pywin32", |
| 5 | + [string]$PyMiRepoUrl="https://github.com/cloudbase/PyMI", |
| 6 | + [string]$BuildDir="" |
| 7 | +) |
| 8 | + |
| 9 | +$ErrorActionPreference = "Stop" |
| 10 | +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 |
| 11 | +$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition |
| 12 | + |
| 13 | +$PIP_BUILD_NO_BINARIES_ARGS = "--no-binary :all:" |
| 14 | + |
| 15 | +function Run-CmdWithRetry { |
| 16 | + param( |
| 17 | + $command, |
| 18 | + [int]$maxRetryCount=3, |
| 19 | + [int]$retryInterval=1 |
| 20 | + ) |
| 21 | + |
| 22 | + $currErrorActionPreference = $ErrorActionPreference |
| 23 | + $ErrorActionPreference = "Continue" |
| 24 | + |
| 25 | + $retryCount = 0 |
| 26 | + while ($true) { |
| 27 | + try { |
| 28 | + & $command |
| 29 | + break |
| 30 | + } catch [System.Exception] { |
| 31 | + $retryCount++ |
| 32 | + if ($retryCount -ge $maxRetryCount) { |
| 33 | + $ErrorActionPreference = $currErrorActionPreference |
| 34 | + throw |
| 35 | + } else { |
| 36 | + Write-Error $_.Exception |
| 37 | + Start-Sleep $retryInterval |
| 38 | + } |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + $ErrorActionPreference = $currErrorActionPreference |
| 43 | +} |
| 44 | + |
| 45 | +function Download-File { |
| 46 | + param( |
| 47 | + $url, |
| 48 | + $dest |
| 49 | + ) |
| 50 | + |
| 51 | + Write-Host "Downloading: $url" |
| 52 | + |
| 53 | + $webClient = New-Object System.Net.webclient |
| 54 | + Run-CmdWithRetry { |
| 55 | + $webClient.DownloadFile($url, $dest) |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +function Set-VCVars { |
| 60 | + param( |
| 61 | + $Version="14.0", |
| 62 | + $Platform="x86_amd64" |
| 63 | + ) |
| 64 | + |
| 65 | + Write-Host "Setting Visual Studio version ${Version} environment variables" |
| 66 | + |
| 67 | + Push-Location "$ENV:ProgramFiles (x86)\Microsoft Visual Studio ${Version}\VC\" |
| 68 | + try { |
| 69 | + cmd /c "vcvarsall.bat $platform & set" | |
| 70 | + ForEach-Object { |
| 71 | + if ($_ -match "=") { |
| 72 | + $v = $_.split("=") |
| 73 | + Set-Item -Force -Path "ENV:\$($v[0])" -Value "$($v[1])" |
| 74 | + } |
| 75 | + } |
| 76 | + } finally { |
| 77 | + Pop-Location |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +function Run-Command { |
| 82 | + param( |
| 83 | + $cmd, |
| 84 | + $arguments, |
| 85 | + $expectedExitCode = 0 |
| 86 | + ) |
| 87 | + |
| 88 | + Write-Host "Executing: $cmd $arguments" |
| 89 | + |
| 90 | + $p = Start-Process -Wait -PassThru ` |
| 91 | + -NoNewWindow $cmd -ArgumentList $arguments |
| 92 | + if ($p.ExitCode -ne $expectedExitCode) { |
| 93 | + throw "$cmd failed with exit code: $($p.ExitCode)" |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +function Clone-Repo { |
| 98 | + param( |
| 99 | + $Url, |
| 100 | + $Destination |
| 101 | + ) |
| 102 | + |
| 103 | + Write-Host "Cloning ${Url} to ${Destination}" |
| 104 | + |
| 105 | + Run-CmdWithRetry { |
| 106 | + try { |
| 107 | + Push-Location $BuildDir |
| 108 | + git clone $Url $Destination |
| 109 | + if ($LastExitCode) { |
| 110 | + throw "git clone ${Url} ${Destination} failed" |
| 111 | + } |
| 112 | + } finally { |
| 113 | + Pop-Location |
| 114 | + } |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +function Install-PythonRequirements { |
| 119 | + param([string]$SourcePath, |
| 120 | + [switch]$BuildWithoutBinaries |
| 121 | + ) |
| 122 | + |
| 123 | + Write-Host "Installing Python requirements from ${SourcePath}" |
| 124 | + |
| 125 | + $extraPipArgs = "" |
| 126 | + if ($BuildWithoutBinaries) { |
| 127 | + $extraPipArgs = $PIP_BUILD_NO_BINARIES_ARGS |
| 128 | + } |
| 129 | + |
| 130 | + Run-CmdWithRetry { |
| 131 | + try { |
| 132 | + Push-Location (Join-Path $BuildDir $SourcePath) |
| 133 | + Run-Command -Cmd "python" -Arguments @("-m", "pip", "install", $extraPipArgs, "-r", ".\requirements.txt") |
| 134 | + } finally { |
| 135 | + Pop-Location |
| 136 | + } |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +function Install-PythonPackage { |
| 141 | + param([string]$SourcePath, |
| 142 | + [switch]$BuildWithoutBinaries |
| 143 | + ) |
| 144 | + |
| 145 | + Write-Host "Installing Python package from ${SourcePath}" |
| 146 | + |
| 147 | + $extraPipArgs = "" |
| 148 | + if ($BuildWithoutBinaries) { |
| 149 | + $extraPipArgs = $PIP_BUILD_NO_BINARIES_ARGS |
| 150 | + } |
| 151 | + |
| 152 | + Run-CmdWithRetry { |
| 153 | + try { |
| 154 | + Push-Location (Join-Path $BuildDir $SourcePath) |
| 155 | + Run-Command -Cmd "python" -Arguments @("-m", "pip", "install", $extraPipArgs, ".") |
| 156 | + } finally { |
| 157 | + Pop-Location |
| 158 | + } |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +function Prepare-BuildDir { |
| 163 | + Write-Host "Creating / Cleaning up build directory ${BuildDir}" |
| 164 | + |
| 165 | + if ($BuildDir -and (Test-Path $BuildDir)) { |
| 166 | + Remove-Item -Recurse -Force $BuildDir |
| 167 | + } |
| 168 | + New-Item -Type Directory -Path $BuildDir -Force | Out-Null |
| 169 | +} |
| 170 | + |
| 171 | +function Setup-PythonPip { |
| 172 | + $env:PIP_CONSTRAINT = "" |
| 173 | + $env:PIP_NO_BINARY = "" |
| 174 | + |
| 175 | + # Update pip. Not needed for latest version of Python 3.7. |
| 176 | + # Download-File "https://bootstrap.pypa.io/get-pip.py" "${BuildDir}/get-pip.py" |
| 177 | + # Run-CmdWithRetry { |
| 178 | + # python "${BuildDir}/get-pip.py" |
| 179 | + # if ($LastExitCode) { |
| 180 | + # throw "Failed to run 'python get-pip.py'" |
| 181 | + # } |
| 182 | + #} |
| 183 | + |
| 184 | + # Cloudbase-Init Python requirements should respect the OpenStack upper constraints |
| 185 | + Clone-Repo "https://github.com/openstack/requirements" "requirements" |
| 186 | + $constraintsFilePath = Join-Path $BuildDir "requirements/upper-constraints.txt" |
| 187 | + |
| 188 | + $env:PIP_CONSTRAINT = $constraintsFilePath |
| 189 | +} |
| 190 | + |
| 191 | +function Install-PyWin32FromSource { |
| 192 | + param($Url) |
| 193 | + |
| 194 | + $sourcePath = "pywin32" |
| 195 | + |
| 196 | + Clone-Repo $Url $sourceFolder |
| 197 | + Install-PythonPackage -SourcePath $sourcePath -BuildWithoutBinaries |
| 198 | +} |
| 199 | + |
| 200 | +function Install-PyMI { |
| 201 | + param($Url) |
| 202 | + |
| 203 | + $sourcePath = "PyMI" |
| 204 | + |
| 205 | + Clone-Repo $Url $sourcePath |
| 206 | + Install-PythonRequirements -SourcePath $sourcePath -BuildWithoutBinaries |
| 207 | + Install-PythonPackage -SourcePath $sourcePath -BuildWithoutBinaries |
| 208 | +} |
| 209 | + |
| 210 | +function Install-CloudbaseInit { |
| 211 | + param($Url) |
| 212 | + |
| 213 | + $sourcePath = "cloudbase-init" |
| 214 | + |
| 215 | + Clone-Repo $Url $sourcePath |
| 216 | + Install-PythonRequirements -SourcePath $sourcePath -BuildWithoutBinaries |
| 217 | + Install-PythonPackage -SourcePath $sourcePath |
| 218 | +} |
| 219 | + |
| 220 | +### Main ### |
| 221 | + |
| 222 | +try { |
| 223 | + $startDate = Get-Date |
| 224 | + Write-Host "Cloudbase-Init build started." |
| 225 | + |
| 226 | + # Make sure that BuildDir is created and cleaned up properly |
| 227 | + if (!$BuildDir) { |
| 228 | + $BuildDir = "build" |
| 229 | + } |
| 230 | + if (![System.IO.Path]::IsPathRooted($BuildDir)) { |
| 231 | + $BuildDir = Join-Path $scriptPath $BuildDir |
| 232 | + } |
| 233 | + Prepare-BuildDir |
| 234 | + |
| 235 | + # Make sure VS 2015 is used |
| 236 | + Set-VCVars -Version "14.0" |
| 237 | + |
| 238 | + # Setup pip upper requirements |
| 239 | + Setup-PythonPip |
| 240 | + |
| 241 | + # Install PyWin32 from source |
| 242 | + Install-PyWin32FromSource $PyWin32RepoUrl |
| 243 | + |
| 244 | + # PyMI setup can be skipped once the upstream version is published on pypi |
| 245 | + Install-PyMI $PyMiRepoUrl |
| 246 | + |
| 247 | + Install-CloudbaseInit $CloudbaseInitRepoUrl |
| 248 | +} finally { |
| 249 | + $endDate = Get-Date |
| 250 | + Write-Host "Cloudbase-Init build finished after $(($endDate - $StartDate).Minutes + 1) minutes." |
| 251 | +} |
| 252 | + |
0 commit comments