forked from learningequality/kolibri
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall_cexts.py
More file actions
executable file
·169 lines (134 loc) · 5.31 KB
/
install_cexts.py
File metadata and controls
executable file
·169 lines (134 loc) · 5.31 KB
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
#!/usr/bin/env python
import argparse
import imp
import os
import shutil
import subprocess
DIST_CEXT = 'kolibri/dist/cext'
PYPI_DOWNLOAD = 'https://pypi.python.org/simple/'
PIWHEEL_DOWNLOAD = 'https://www.piwheels.hostedpi.com/simple/'
"""
Check if requests and bs4 modules are installed.
"""
def _install_requests_and_bs4_if_needed():
try:
imp.find_module('requests')
print ('requests module exists')
except ImportError:
subprocess.call(['pip', 'install', 'requests'])
try:
imp.find_module('bs4')
print ('bs4 module exists')
except ImportError:
subprocess.call(['pip', 'install', 'bs4'])
def get_path_with_arch(platform, path):
"""
Distribute packages into folders according to the platform.
"""
# Change the platform name into correct formats
platform = platform.replace('_', '-')
platform = platform.replace('x86-64', 'x86_64')
platform = platform.replace('manylinux1', 'linux')
# For cryptography module, all the macosxs >= 10.9 are supported
if 'macosx' in platform:
platform = 'macosx'
path = os.path.join(path, platform)
return path
def download_package(path, platform, version, implementation, abi, name):
"""
Download the package according to platform, python version, implementation and abi.
"""
if 'arm' in platform:
index_url = PIWHEEL_DOWNLOAD
else:
index_url = PYPI_DOWNLOAD
return_code = subprocess.call([
'python', 'kolibripip.pex', 'download', '-q', '-d', path, '--platform', platform,
'--python-version', version, '--implementation', implementation,
'--abi', abi, '-i', index_url, name
])
return return_code
def install_package_by_wheel(path, name):
"""
Install the package using the cached wheel files.
"""
return_code = subprocess.call([
'python', 'kolibripip.pex', 'install', '-q', '-t',
path, os.path.join(path, name)
])
if return_code == 1:
print ('Installation failed for package {}\n'.format(name))
else:
# Clean up all the whl files and dist-info folders in the directory
for item in os.listdir(path):
if item.endswith('.whl'):
os.remove(os.path.join(path, item))
elif item.endswith('dist-info'):
shutil.rmtree(os.path.join(path, item), ignore_errors=True)
def parse_package_page(files, pk_version):
"""
Parse the PYPI and Piwheel link for the package and install the desired wheel files.
"""
for file in files.find_all('a'):
file_name = file.string.split('-')
# If the file format is tar.gz or the package version is not the latest, ignore
if file_name[-1].split('.')[-1] != 'whl' or file_name[1] != pk_version or file_name[2][2:] == '26':
continue
print ('Installing {}...'.format(file.string))
implementation = file_name[2][:2]
python_version = file_name[2][2:]
path = os.path.join(DIST_CEXT, file_name[2])
abi = file_name[3]
platform = file_name[4].split('.')[0]
# Prior to CPython 3.3, there were two ABI-incompatible ways of building CPython
if 'linux' in platform and implementation == 'cp' and int(python_version) < 33:
# There could be abi tag 'm' for narrow-unicode and abi tag 'mu' for wide-unicode
path = os.path.join(os.path.join(path, 'linux'), abi)
path = get_path_with_arch(platform, path)
if path == '':
# Package is not supported in this platform
continue
download_return = download_package(
path, platform, python_version, implementation, abi, file_name[0]
)
# Successfully downloaded package
if download_return == 0:
install_package_by_wheel(path, file.string)
# Download failed
else:
print ('Download failed for package {}\n'.format(file.string))
def install(name, pk_version):
"""
Start installing from the pypi page of the package.
"""
_install_requests_and_bs4_if_needed()
try:
import requests
from bs4 import BeautifulSoup
# Parse everything in the package repo in both pypi and piwheel
links = [PYPI_DOWNLOAD, PIWHEEL_DOWNLOAD]
for link in links:
r = requests.get(link + name)
files = BeautifulSoup(r.content, 'html.parser')
parse_package_page(files, pk_version)
except ImportError:
raise ImportError('Importing modules failed.\n')
def parse_requirements(args):
"""
Parse the requirements.txt to get packages' names and versions,
then install them.
"""
with open(args.file) as f:
for line in f:
char_list = line.split('==')
if len(char_list) == 2:
# Install package according to its name and version
install(char_list[0], char_list[1])
else:
print ('Name format is incorrect. Should be \'packageName==packageVersion\'.')
if __name__ == '__main__':
# Parsing the requirement.txt file argument
parser = argparse.ArgumentParser(description="Downloading and installing Python C extensions tool.")
parser.add_argument('--file', required=True, help='The name of the requirements.txt')
args = parser.parse_args()
parse_requirements(args)