| <# | |
| .Synopsis | |
| Uploads from a VSTS release build layout to python.org | |
| .Description | |
| Given the downloaded/extracted build artifact from a release | |
| build run on python.visualstudio.com, this script uploads | |
| the files to the correct locations. | |
| .Parameter build | |
| The location on disk of the extracted build artifact. | |
| .Parameter user | |
| The username to use when logging into the host. | |
| .Parameter server | |
| The host or PuTTY session name. | |
| .Parameter target | |
| The subdirectory on the host to copy files to. | |
| .Parameter tests | |
| The path to run download tests in. | |
| .Parameter doc_htmlhelp | |
| Optional path besides -build to locate CHM files. | |
| .Parameter embed | |
| Optional path besides -build to locate ZIP files. | |
| .Parameter skipupload | |
| Skip uploading | |
| .Parameter skippurge | |
| Skip purging the CDN | |
| .Parameter skiptest | |
| Skip the download tests | |
| .Parameter skiphash | |
| Skip displaying hashes | |
| #> | |
| param( | |
| [Parameter(Mandatory=$true)][string]$build, | |
| [Parameter(Mandatory=$true)][string]$user, | |
| [string]$server="python-downloads", | |
| [string]$target="/srv/www.python.org/ftp/python", | |
| [string]$tests=${env:TEMP}, | |
| [string]$doc_htmlhelp=$null, | |
| [string]$embed=$null, | |
| [switch]$skipupload, | |
| [switch]$skippurge, | |
| [switch]$skiptest, | |
| [switch]$skiphash | |
| ) | |
| if (-not $build) { throw "-build option is required" } | |
| if (-not $user) { throw "-user option is required" } | |
| $tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent; | |
| if (-not ((Test-Path "$build\win32\python-*.exe") -or (Test-Path "$build\amd64\python-*.exe"))) { | |
| throw "-build argument does not look like a 'build' directory" | |
| } | |
| function find-putty-tool { | |
| param ([string]$n) | |
| $t = gcm $n -EA 0 | |
| if (-not $t) { $t = gcm ".\$n" -EA 0 } | |
| if (-not $t) { $t = gcm "${env:ProgramFiles}\PuTTY\$n" -EA 0 } | |
| if (-not $t) { $t = gcm "${env:ProgramFiles(x86)}\PuTTY\$n" -EA 0 } | |
| if (-not $t) { throw "Unable to locate $n.exe. Please put it on $PATH" } | |
| return gi $t.Path | |
| } | |
| $p = gci -r "$build\python-*.exe" | ` | |
| ?{ $_.Name -match '^python-(\d+\.\d+\.\d+)((a|b|rc)\d+)?-.+' } | ` | |
| select -first 1 | ` | |
| %{ $Matches[1], $Matches[2] } | |
| "Uploading version $($p[0]) $($p[1])" | |
| " from: $build" | |
| " to: $($server):$target/$($p[0])" | |
| "" | |
| if (-not $skipupload) { | |
| # Upload files to the server | |
| $pscp = find-putty-tool "pscp" | |
| $plink = find-putty-tool "plink" | |
| "Upload using $pscp and $plink" | |
| "" | |
| if ($doc_htmlhelp) { | |
| $chm = gci -EA 0 $doc_htmlhelp\python*.chm, $doc_htmlhelp\python*.chm.asc | |
| } else { | |
| $chm = gci -EA 0 $build\python*.chm, $build\python*.chm.asc | |
| } | |
| $d = "$target/$($p[0])/" | |
| & $plink -batch $user@$server mkdir $d | |
| & $plink -batch $user@$server chgrp downloads $d | |
| & $plink -batch $user@$server chmod o+rx $d | |
| if ($chm) { | |
| & $pscp -batch $chm.FullName "$user@${server}:$d" | |
| if (-not $?) { throw "Failed to upload $chm" } | |
| } | |
| $dirs = gci "$build" -Directory | |
| if ($embed) { | |
| $dirs = ($dirs, (gi $embed)) | %{ $_ } | |
| } | |
| foreach ($a in $dirs) { | |
| "Uploading files from $($a.FullName)" | |
| pushd "$($a.FullName)" | |
| $exe = gci *.exe, *.exe.asc, *.zip, *.zip.asc | |
| $msi = gci *.msi, *.msi.asc, *.msu, *.msu.asc | |
| popd | |
| if ($exe) { | |
| & $pscp -batch $exe.FullName "$user@${server}:$d" | |
| if (-not $?) { throw "Failed to upload $exe" } | |
| } | |
| if ($msi) { | |
| $sd = "$d$($a.Name)$($p[1])/" | |
| & $plink -batch $user@$server mkdir $sd | |
| & $plink -batch $user@$server chgrp downloads $sd | |
| & $plink -batch $user@$server chmod o+rx $sd | |
| & $pscp -batch $msi.FullName "$user@${server}:$sd" | |
| if (-not $?) { throw "Failed to upload $msi" } | |
| & $plink -batch $user@$server chgrp downloads $sd* | |
| & $plink -batch $user@$server chmod g-x,o+r $sd* | |
| } | |
| } | |
| & $plink -batch $user@$server chgrp downloads $d* | |
| & $plink -batch $user@$server chmod g-x,o+r $d* | |
| & $pscp -ls "$user@${server}:$d" | |
| } | |
| if (-not $skippurge) { | |
| # Run a CDN purge | |
| py $tools\purge.py "$($p[0])$($p[1])" | |
| } | |
| if (-not $skiptest) { | |
| # Use each web installer to produce a layout. This will download | |
| # each referenced file and validate their signatures/hashes. | |
| gci "$build\*-webinstall.exe" -r -File | %{ | |
| $d = mkdir "$tests\$($_.BaseName)" -Force | |
| gci $d -r -File | del | |
| $ic = copy $_ $d -PassThru | |
| "Checking layout for $($ic.Name)" | |
| Start-Process -wait $ic "/passive", "/layout", "$d\layout", "/log", "$d\log\install.log" | |
| if (-not $?) { | |
| Write-Error "Failed to validate layout of $($inst.Name)" | |
| } | |
| } | |
| } | |
| if (-not $skiphash) { | |
| # Display MD5 hash and size of each downloadable file | |
| pushd $build | |
| $files = gci python*.chm, *\*.exe, *\*.zip | |
| if ($doc_htmlhelp) { | |
| cd $doc_htmlhelp | |
| $files = ($files, (gci python*.chm)) | %{ $_ } | |
| } | |
| if ($embed) { | |
| cd $embed | |
| $files = ($files, (gci *.zip)) | %{ $_ } | |
| } | |
| popd | |
| $hashes = $files | ` | |
| Sort-Object Name | ` | |
| Format-Table Name, @{Label="MD5"; Expression={(Get-FileHash $_ -Algorithm MD5).Hash}}, Length -AutoSize | ` | |
| Out-String -Width 4096 | |
| $hashes | clip | |
| $hashes | |
| } |