uploadrelease.ps1 4.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<#
.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.
18 19 20 21
.Parameter doc_htmlhelp
    Optional path besides -build to locate CHM files.
.Parameter embed
    Optional path besides -build to locate ZIP files.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
.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},
37 38
    [string]$doc_htmlhelp=$null,
    [string]$embed=$null,
39 40 41 42 43 44 45 46 47
    [switch]$skipupload,
    [switch]$skippurge,
    [switch]$skiptest,
    [switch]$skiphash
)

if (-not $build) { throw "-build option is required" }
if (-not $user) { throw "-user option is required" }

48 49
$tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent;

50 51 52 53
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"
}

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
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"

79 80 81
    "Upload using $pscp and $plink"
    ""

82 83 84 85 86 87
    if ($doc_htmlhelp) {
        pushd $doc_htmlhelp
    } else {
        pushd $build
    }
    $chm = gci python*.chm, python*.chm.asc
88 89 90
    popd

    $d = "$target/$($p[0])/"
91 92 93
    & $plink -batch $user@$server mkdir $d
    & $plink -batch $user@$server chgrp downloads $d
    & $plink -batch $user@$server chmod g-x,o+rx $d
94
    & $pscp -batch $chm.FullName "$user@${server}:$d"
95

96 97 98 99 100 101
    $dirs = gci "$build" -Directory
    if ($embed) {
        $dirs = ($dirs, (gi $embed)) | %{ $_ }
    }

    foreach ($a in $dirs) {
102 103 104 105 106 107
        "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

108 109 110
        if ($exe) {
            & $pscp -batch $exe.FullName "$user@${server}:$d"
        }
111

112 113 114 115 116 117 118 119 120
        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 g-x,o+rx $sd
            & $pscp -batch $msi.FullName "$user@${server}:$sd"
            & $plink -batch $user@$server chgrp downloads $sd*
            & $plink -batch $user@$server chmod g-x,o+r $sd*
        }
121 122
    }

123 124
    & $plink -batch $user@$server chgrp downloads $d*
    & $plink -batch $user@$server chmod g-x,o+r $d*
125 126 127 128
}

if (-not $skippurge) {
    # Run a CDN purge
129
    py $tools\purge.py "$($p[0])$($p[1])"
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
}

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
150 151 152 153 154 155 156 157 158 159 160 161
    $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 | `
162
        Sort-Object Name | `
163 164 165 166
        Format-Table Name, @{Label="MD5"; Expression={(Get-FileHash $_ -Algorithm MD5).Hash}}, Length -AutoSize | `
        Out-String -Width 4096
    $hashes | clip
    $hashes
167
}