1#!/usr/bin/env python3 2 3# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7""" 8Script which downloads wheel files hosted on AppVeyor: 9https://ci.appveyor.com/project/giampaolo/psutil 10Readapted from the original recipe of Ibarra Corretge' 11<saghul@gmail.com>: 12http://code.saghul.net/index.php/2015/09/09/ 13""" 14 15from __future__ import print_function 16import concurrent.futures 17import os 18import requests 19import sys 20 21from psutil import __version__ as PSUTIL_VERSION 22from psutil._common import bytes2human 23from psutil._common import print_color 24 25 26USER = "giampaolo" 27PROJECT = "psutil" 28BASE_URL = 'https://ci.appveyor.com/api' 29PY_VERSIONS = ['2.7', '3.6', '3.7', '3.8', '3.9'] 30TIMEOUT = 30 31 32 33def download_file(url): 34 local_fname = url.split('/')[-1] 35 local_fname = os.path.join('dist', local_fname) 36 os.makedirs('dist', exist_ok=True) 37 r = requests.get(url, stream=True, timeout=TIMEOUT) 38 tot_bytes = 0 39 with open(local_fname, 'wb') as f: 40 for chunk in r.iter_content(chunk_size=16384): 41 if chunk: # filter out keep-alive new chunks 42 f.write(chunk) 43 tot_bytes += len(chunk) 44 return local_fname 45 46 47def get_file_urls(): 48 with requests.Session() as session: 49 data = session.get( 50 BASE_URL + '/projects/' + USER + '/' + PROJECT, 51 timeout=TIMEOUT) 52 data = data.json() 53 54 urls = [] 55 for job in (job['jobId'] for job in data['build']['jobs']): 56 job_url = BASE_URL + '/buildjobs/' + job + '/artifacts' 57 data = session.get(job_url, timeout=TIMEOUT) 58 data = data.json() 59 for item in data: 60 file_url = job_url + '/' + item['fileName'] 61 urls.append(file_url) 62 if not urls: 63 print_color("no artifacts found", 'red') 64 sys.exit(1) 65 else: 66 for url in sorted(urls, key=lambda x: os.path.basename(x)): 67 yield url 68 69 70def rename_win27_wheels(): 71 # See: https://github.com/giampaolo/psutil/issues/810 72 src = 'dist/psutil-%s-cp27-cp27m-win32.whl' % PSUTIL_VERSION 73 dst = 'dist/psutil-%s-cp27-none-win32.whl' % PSUTIL_VERSION 74 print("rename: %s\n %s" % (src, dst)) 75 os.rename(src, dst) 76 src = 'dist/psutil-%s-cp27-cp27m-win_amd64.whl' % PSUTIL_VERSION 77 dst = 'dist/psutil-%s-cp27-none-win_amd64.whl' % PSUTIL_VERSION 78 print("rename: %s\n %s" % (src, dst)) 79 os.rename(src, dst) 80 81 82def run(): 83 urls = get_file_urls() 84 completed = 0 85 exc = None 86 with concurrent.futures.ThreadPoolExecutor() as e: 87 fut_to_url = {e.submit(download_file, url): url for url in urls} 88 for fut in concurrent.futures.as_completed(fut_to_url): 89 url = fut_to_url[fut] 90 try: 91 local_fname = fut.result() 92 except Exception: 93 print_color("error while downloading %s" % (url), 'red') 94 raise 95 else: 96 completed += 1 97 print("downloaded %-45s %s" % ( 98 local_fname, bytes2human(os.path.getsize(local_fname)))) 99 # 2 wheels (32 and 64 bit) per supported python version 100 expected = len(PY_VERSIONS) * 2 101 if expected != completed: 102 return exit("expected %s files, got %s" % (expected, completed)) 103 if exc: 104 return exit() 105 rename_win27_wheels() 106 107 108def main(): 109 run() 110 111 112if __name__ == '__main__': 113 main() 114