summaryrefslogtreecommitdiffstats
path: root/Tools/msi/uploadrelease.ps1
blob: a8669e5d65ed14b2ea2d09d5ea8bf93bea361fbd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<#
.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
}