1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
3
4"""Use the Appveyor API to download Windows artifacts."""
5
6import os
7import os.path
8import sys
9import zipfile
10
11import requests
12
13
14def make_auth_headers():
15    """Make the authentication headers needed to use the Appveyor API."""
16    with open("ci/appveyor.token") as f:
17        token = f.read().strip()
18
19    headers = {
20        'Authorization': 'Bearer {}'.format(token),
21    }
22    return headers
23
24
25def make_url(url, **kwargs):
26    """Build an Appveyor API url."""
27    return "https://ci.appveyor.com/api" + url.format(**kwargs)
28
29
30def get_project_build(account_project):
31    """Get the details of the latest Appveyor build."""
32    url = make_url("/projects/{account_project}", account_project=account_project)
33    response = requests.get(url, headers=make_auth_headers())
34    return response.json()
35
36
37def download_latest_artifacts(account_project):
38    """Download all the artifacts from the latest build."""
39    build = get_project_build(account_project)
40    jobs = build['build']['jobs']
41    print("Build {0[build][version]}, {1} jobs: {0[build][message]}".format(build, len(jobs)))
42    for job in jobs:
43        name = job['name'].partition(':')[2].split(',')[0].strip()
44        print("  {0}: {1[status]}, {1[artifactsCount]} artifacts".format(name, job))
45
46        url = make_url("/buildjobs/{jobid}/artifacts", jobid=job['jobId'])
47        response = requests.get(url, headers=make_auth_headers())
48        artifacts = response.json()
49
50        for artifact in artifacts:
51            is_zip = artifact['type'] == "Zip"
52            filename = artifact['fileName']
53            print("    {}, {} bytes".format(filename, artifact['size']))
54
55            url = make_url(
56                "/buildjobs/{jobid}/artifacts/{filename}",
57                jobid=job['jobId'],
58                filename=filename
59            )
60            download_url(url, filename, make_auth_headers())
61
62            if is_zip:
63                unpack_zipfile(filename)
64                os.remove(filename)
65
66
67def ensure_dirs(filename):
68    """Make sure the directories exist for `filename`."""
69    dirname, _ = os.path.split(filename)
70    if dirname and not os.path.exists(dirname):
71        os.makedirs(dirname)
72
73
74def download_url(url, filename, headers):
75    """Download a file from `url` to `filename`."""
76    ensure_dirs(filename)
77    response = requests.get(url, headers=headers, stream=True)
78    if response.status_code == 200:
79        with open(filename, 'wb') as f:
80            for chunk in response.iter_content(16*1024):
81                f.write(chunk)
82
83
84def unpack_zipfile(filename):
85    """Unpack a zipfile, using the names in the zip."""
86    with open(filename, 'rb') as fzip:
87        z = zipfile.ZipFile(fzip)
88        for name in z.namelist():
89            print("      extracting {}".format(name))
90            ensure_dirs(name)
91            z.extract(name)
92
93
94if __name__ == "__main__":
95    download_latest_artifacts(sys.argv[1])
96