1# Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2# file at the top-level directory of this distribution. 3# 4# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 5# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 6# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 7# option. This file may not be copied, modified, or distributed 8# except according to those terms. 9 10from __future__ import absolute_import, print_function, unicode_literals 11 12import os 13import os.path 14import platform 15import shutil 16from socket import error as socket_error 17import stat 18import StringIO 19import sys 20import zipfile 21import urllib2 22import certifi 23 24 25try: 26 from ssl import HAS_SNI 27except ImportError: 28 HAS_SNI = False 29 30# The cafile parameter was added in 2.7.9 31if HAS_SNI and sys.version_info >= (2, 7, 9): 32 STATIC_RUST_LANG_ORG_DIST = "https://static.rust-lang.org/dist" 33 URLOPEN_KWARGS = {"cafile": certifi.where()} 34else: 35 STATIC_RUST_LANG_ORG_DIST = "https://static-rust-lang-org.s3.amazonaws.com/dist" 36 URLOPEN_KWARGS = {} 37 38 39def remove_readonly(func, path, _): 40 "Clear the readonly bit and reattempt the removal" 41 os.chmod(path, stat.S_IWRITE) 42 func(path) 43 44 45def delete(path): 46 if os.path.isdir(path) and not os.path.islink(path): 47 shutil.rmtree(path, onerror=remove_readonly) 48 else: 49 os.remove(path) 50 51 52def host_platform(): 53 os_type = platform.system().lower() 54 if os_type == "linux": 55 os_type = "unknown-linux-gnu" 56 elif os_type == "darwin": 57 os_type = "apple-darwin" 58 elif os_type == "android": 59 os_type = "linux-androideabi" 60 elif os_type == "windows": 61 os_type = "pc-windows-msvc" 62 elif os_type == "freebsd": 63 os_type = "unknown-freebsd" 64 else: 65 os_type = "unknown" 66 return os_type 67 68 69def host_triple(): 70 os_type = host_platform() 71 cpu_type = platform.machine().lower() 72 if cpu_type in ["i386", "i486", "i686", "i768", "x86"]: 73 cpu_type = "i686" 74 elif cpu_type in ["x86_64", "x86-64", "x64", "amd64"]: 75 cpu_type = "x86_64" 76 elif cpu_type == "arm": 77 cpu_type = "arm" 78 elif cpu_type == "aarch64": 79 cpu_type = "aarch64" 80 else: 81 cpu_type = "unknown" 82 83 return "{}-{}".format(cpu_type, os_type) 84 85 86def download(desc, src, writer, start_byte=0): 87 if start_byte: 88 print("Resuming download of {} ...".format(src)) 89 else: 90 print("Downloading {} ...".format(src)) 91 dumb = (os.environ.get("TERM") == "dumb") or (not sys.stdout.isatty()) 92 93 try: 94 req = urllib2.Request(src) 95 if start_byte: 96 req = urllib2.Request(src, headers={'Range': 'bytes={}-'.format(start_byte)}) 97 resp = urllib2.urlopen(req, **URLOPEN_KWARGS) 98 99 fsize = None 100 if resp.info().getheader('Content-Length'): 101 fsize = int(resp.info().getheader('Content-Length').strip()) + start_byte 102 103 recved = start_byte 104 chunk_size = 8192 105 106 while True: 107 chunk = resp.read(chunk_size) 108 if not chunk: 109 break 110 recved += len(chunk) 111 if not dumb: 112 if fsize is not None: 113 pct = recved * 100.0 / fsize 114 print("\rDownloading %s: %5.1f%%" % (desc, pct), end="") 115 116 sys.stdout.flush() 117 writer.write(chunk) 118 119 if not dumb: 120 print() 121 except urllib2.HTTPError, e: 122 print("Download failed ({}): {} - {}".format(e.code, e.reason, src)) 123 if e.code == 403: 124 print("No Rust compiler binary available for this platform. " 125 "Please see https://github.com/servo/servo/#prerequisites") 126 sys.exit(1) 127 except urllib2.URLError, e: 128 print("Error downloading {}: {}. The failing URL was: {}".format(desc, e.reason, src)) 129 sys.exit(1) 130 except socket_error, e: 131 print("Looks like there's a connectivity issue, check your Internet connection. {}".format(e)) 132 sys.exit(1) 133 except KeyboardInterrupt: 134 writer.flush() 135 raise 136 137 138def download_bytes(desc, src): 139 content_writer = StringIO.StringIO() 140 download(desc, src, content_writer) 141 return content_writer.getvalue() 142 143 144def download_file(desc, src, dst): 145 tmp_path = dst + ".part" 146 try: 147 start_byte = os.path.getsize(tmp_path) 148 with open(tmp_path, 'ab') as fd: 149 download(desc, src, fd, start_byte=start_byte) 150 except os.error: 151 with open(tmp_path, 'wb') as fd: 152 download(desc, src, fd) 153 os.rename(tmp_path, dst) 154 155 156def extract(src, dst, movedir=None): 157 assert src.endswith(".zip") 158 zipfile.ZipFile(src).extractall(dst) 159 160 if movedir: 161 for f in os.listdir(movedir): 162 frm = os.path.join(movedir, f) 163 to = os.path.join(dst, f) 164 os.rename(frm, to) 165 os.rmdir(movedir) 166 167 os.remove(src) 168