|
a |
|
b/ci/appveyor-bootstrap.py |
|
|
1 |
""" |
|
|
2 |
AppVeyor will at least have few Pythons around so there's no point of implementing a bootstrapper in PowerShell. |
|
|
3 |
|
|
|
4 |
This is a port of https://github.com/pypa/python-packaging-user-guide/blob/master/source/code/install.ps1 |
|
|
5 |
with various fixes and improvements that just weren't feasible to implement in PowerShell. |
|
|
6 |
""" |
|
|
7 |
from __future__ import print_function |
|
|
8 |
from os import environ |
|
|
9 |
from os.path import exists |
|
|
10 |
from subprocess import check_call |
|
|
11 |
|
|
|
12 |
try: |
|
|
13 |
from urllib.request import urlretrieve |
|
|
14 |
except ImportError: |
|
|
15 |
from urllib import urlretrieve |
|
|
16 |
|
|
|
17 |
BASE_URL = "https://www.python.org/ftp/python/" |
|
|
18 |
GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" |
|
|
19 |
GET_PIP_PATH = "C:\get-pip.py" |
|
|
20 |
URLS = { |
|
|
21 |
("2.7", "64"): BASE_URL + "2.7.13/python-2.7.13.amd64.msi", |
|
|
22 |
("2.7", "32"): BASE_URL + "2.7.13/python-2.7.13.msi", |
|
|
23 |
# NOTE: no .msi installer for 3.3.6 |
|
|
24 |
("3.3", "64"): BASE_URL + "3.3.5/python-3.3.5.amd64.msi", |
|
|
25 |
("3.3", "32"): BASE_URL + "3.3.5/python-3.3.5.msi", |
|
|
26 |
("3.4", "64"): BASE_URL + "3.4.4/python-3.4.4.amd64.msi", |
|
|
27 |
("3.4", "32"): BASE_URL + "3.4.4/python-3.4.4.msi", |
|
|
28 |
("3.5", "64"): BASE_URL + "3.5.4/python-3.5.4-amd64.exe", |
|
|
29 |
("3.5", "32"): BASE_URL + "3.5.4/python-3.5.4.exe", |
|
|
30 |
("3.6", "64"): BASE_URL + "3.6.2/python-3.6.2-amd64.exe", |
|
|
31 |
("3.6", "32"): BASE_URL + "3.6.2/python-3.6.2.exe", |
|
|
32 |
} |
|
|
33 |
INSTALL_CMD = { |
|
|
34 |
# Commands are allowed to fail only if they are not the last command. Eg: uninstall (/x) allowed to fail. |
|
|
35 |
"2.7": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], |
|
|
36 |
["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], |
|
|
37 |
"3.3": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], |
|
|
38 |
["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], |
|
|
39 |
"3.4": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], |
|
|
40 |
["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], |
|
|
41 |
"3.5": [["{path}", "/quiet", "TargetDir={home}"]], |
|
|
42 |
"3.6": [["{path}", "/quiet", "TargetDir={home}"]], |
|
|
43 |
} |
|
|
44 |
|
|
|
45 |
|
|
|
46 |
def download_file(url, path): |
|
|
47 |
print("Downloading: {} (into {})".format(url, path)) |
|
|
48 |
progress = [0, 0] |
|
|
49 |
|
|
|
50 |
def report(count, size, total): |
|
|
51 |
progress[0] = count * size |
|
|
52 |
if progress[0] - progress[1] > 1000000: |
|
|
53 |
progress[1] = progress[0] |
|
|
54 |
print("Downloaded {:,}/{:,} ...".format(progress[1], total)) |
|
|
55 |
|
|
|
56 |
dest, _ = urlretrieve(url, path, reporthook=report) |
|
|
57 |
return dest |
|
|
58 |
|
|
|
59 |
|
|
|
60 |
def install_python(version, arch, home): |
|
|
61 |
print("Installing Python", version, "for", arch, "bit architecture to", home) |
|
|
62 |
if exists(home): |
|
|
63 |
return |
|
|
64 |
|
|
|
65 |
path = download_python(version, arch) |
|
|
66 |
print("Installing", path, "to", home) |
|
|
67 |
success = False |
|
|
68 |
for cmd in INSTALL_CMD[version]: |
|
|
69 |
cmd = [part.format(home=home, path=path) for part in cmd] |
|
|
70 |
print("Running:", " ".join(cmd)) |
|
|
71 |
try: |
|
|
72 |
check_call(cmd) |
|
|
73 |
except Exception as exc: |
|
|
74 |
print("Failed command", cmd, "with:", exc) |
|
|
75 |
if exists("install.log"): |
|
|
76 |
with open("install.log") as fh: |
|
|
77 |
print(fh.read()) |
|
|
78 |
else: |
|
|
79 |
success = True |
|
|
80 |
if success: |
|
|
81 |
print("Installation complete!") |
|
|
82 |
else: |
|
|
83 |
print("Installation failed") |
|
|
84 |
|
|
|
85 |
|
|
|
86 |
def download_python(version, arch): |
|
|
87 |
for _ in range(3): |
|
|
88 |
try: |
|
|
89 |
return download_file(URLS[version, arch], "installer.exe") |
|
|
90 |
except Exception as exc: |
|
|
91 |
print("Failed to download:", exc) |
|
|
92 |
print("Retrying ...") |
|
|
93 |
|
|
|
94 |
|
|
|
95 |
def install_pip(home): |
|
|
96 |
pip_path = home + "/Scripts/pip.exe" |
|
|
97 |
python_path = home + "/python.exe" |
|
|
98 |
if exists(pip_path): |
|
|
99 |
print("pip already installed.") |
|
|
100 |
else: |
|
|
101 |
print("Installing pip...") |
|
|
102 |
download_file(GET_PIP_URL, GET_PIP_PATH) |
|
|
103 |
print("Executing:", python_path, GET_PIP_PATH) |
|
|
104 |
check_call([python_path, GET_PIP_PATH]) |
|
|
105 |
|
|
|
106 |
|
|
|
107 |
def install_packages(home, *packages): |
|
|
108 |
cmd = [home + "/Scripts/pip.exe", "install"] |
|
|
109 |
cmd.extend(packages) |
|
|
110 |
check_call(cmd) |
|
|
111 |
|
|
|
112 |
|
|
|
113 |
if __name__ == "__main__": |
|
|
114 |
install_python(environ['PYTHON_VERSION'], environ['PYTHON_ARCH'], environ['PYTHON_HOME']) |
|
|
115 |
install_pip(environ['PYTHON_HOME']) |
|
|
116 |
install_packages(environ['PYTHON_HOME'], "setuptools>=18.0.1", "wheel", "tox", "virtualenv>=13.1.0") |