|
@@ -3,6 +3,8 @@ |
|
@@ -3,6 +3,8 @@ |
3
|
"""
|
3
|
"""
|
4
|
Setuptools bootstrapping installer.
|
4
|
Setuptools bootstrapping installer.
|
5
|
|
5
|
|
|
|
6
|
+Maintained at https://github.com/pypa/setuptools/tree/bootstrap.
|
|
|
7
|
+
|
6
|
Run this script to install or upgrade setuptools.
|
8
|
Run this script to install or upgrade setuptools.
|
7
|
"""
|
9
|
"""
|
8
|
|
10
|
|
|
@@ -16,24 +18,30 @@ import subprocess |
|
@@ -16,24 +18,30 @@ import subprocess |
16
|
import platform
|
18
|
import platform
|
17
|
import textwrap
|
19
|
import textwrap
|
18
|
import contextlib
|
20
|
import contextlib
|
19
|
-import warnings
|
21
|
+import json
|
|
|
22
|
+import codecs
|
20
|
|
23
|
|
21
|
from distutils import log
|
24
|
from distutils import log
|
22
|
|
25
|
|
23
|
try:
|
26
|
try:
|
24
|
from urllib.request import urlopen
|
27
|
from urllib.request import urlopen
|
|
|
28
|
+ from urllib.parse import urljoin
|
25
|
except ImportError:
|
29
|
except ImportError:
|
26
|
from urllib2 import urlopen
|
30
|
from urllib2 import urlopen
|
|
|
31
|
+ from urlparse import urljoin
|
27
|
|
32
|
|
28
|
try:
|
33
|
try:
|
29
|
from site import USER_SITE
|
34
|
from site import USER_SITE
|
30
|
except ImportError:
|
35
|
except ImportError:
|
31
|
USER_SITE = None
|
36
|
USER_SITE = None
|
32
|
|
37
|
|
|
|
38
|
+LATEST = object()
|
33
|
DEFAULT_VERSION = "18.3.2"
|
39
|
DEFAULT_VERSION = "18.3.2"
|
34
|
-DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
|
40
|
+DEFAULT_URL = "https://pypi.io/packages/source/s/setuptools/"
|
35
|
DEFAULT_SAVE_DIR = os.curdir
|
41
|
DEFAULT_SAVE_DIR = os.curdir
|
36
|
|
42
|
|
|
|
43
|
+MEANINGFUL_INVALID_ZIP_ERR_MSG = 'Maybe {0} is corrupted, delete it and try again.'
|
|
|
44
|
+
|
37
|
|
45
|
|
38
|
def _python_cmd(*args):
|
46
|
def _python_cmd(*args):
|
39
|
"""
|
47
|
"""
|
|
@@ -98,8 +106,16 @@ def archive_context(filename): |
|
@@ -98,8 +106,16 @@ def archive_context(filename): |
98
|
old_wd = os.getcwd()
|
106
|
old_wd = os.getcwd()
|
99
|
try:
|
107
|
try:
|
100
|
os.chdir(tmpdir)
|
108
|
os.chdir(tmpdir)
|
101
|
- with ContextualZipFile(filename) as archive:
|
|
|
102
|
- archive.extractall()
|
109
|
+ try:
|
|
|
110
|
+ with ContextualZipFile(filename) as archive:
|
|
|
111
|
+ archive.extractall()
|
|
|
112
|
+ except zipfile.BadZipfile as err:
|
|
|
113
|
+ if not err.args:
|
|
|
114
|
+ err.args = ('', )
|
|
|
115
|
+ err.args = err.args + (
|
|
|
116
|
+ MEANINGFUL_INVALID_ZIP_ERR_MSG.format(filename),
|
|
|
117
|
+ )
|
|
|
118
|
+ raise
|
103
|
|
119
|
|
104
|
# going in the directory
|
120
|
# going in the directory
|
105
|
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
121
|
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
|
@@ -114,18 +130,19 @@ def archive_context(filename): |
|
@@ -114,18 +130,19 @@ def archive_context(filename): |
114
|
|
130
|
|
115
|
def _do_download(version, download_base, to_dir, download_delay):
|
131
|
def _do_download(version, download_base, to_dir, download_delay):
|
116
|
"""Download Setuptools."""
|
132
|
"""Download Setuptools."""
|
117
|
- egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg'
|
|
|
118
|
- % (version, sys.version_info[0], sys.version_info[1]))
|
133
|
+ py_desig = 'py{sys.version_info[0]}.{sys.version_info[1]}'.format(sys=sys)
|
|
|
134
|
+ tp = 'setuptools-{version}-{py_desig}.egg'
|
|
|
135
|
+ egg = os.path.join(to_dir, tp.format(**locals()))
|
119
|
if not os.path.exists(egg):
|
136
|
if not os.path.exists(egg):
|
120
|
archive = download_setuptools(version, download_base,
|
137
|
archive = download_setuptools(version, download_base,
|
121
|
- to_dir, download_delay)
|
138
|
+ to_dir, download_delay)
|
122
|
_build_egg(egg, archive, to_dir)
|
139
|
_build_egg(egg, archive, to_dir)
|
123
|
sys.path.insert(0, egg)
|
140
|
sys.path.insert(0, egg)
|
124
|
|
141
|
|
125
|
# Remove previously-imported pkg_resources if present (see
|
142
|
# Remove previously-imported pkg_resources if present (see
|
126
|
# https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
|
143
|
# https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
|
127
|
if 'pkg_resources' in sys.modules:
|
144
|
if 'pkg_resources' in sys.modules:
|
128
|
- del sys.modules['pkg_resources']
|
145
|
+ _unload_pkg_resources()
|
129
|
|
146
|
|
130
|
import setuptools
|
147
|
import setuptools
|
131
|
setuptools.bootstrap_install_from = egg
|
148
|
setuptools.bootstrap_install_from = egg
|
|
@@ -140,6 +157,7 @@ def use_setuptools( |
|
@@ -140,6 +157,7 @@ def use_setuptools( |
140
|
Return None. Raise SystemExit if the requested version
|
157
|
Return None. Raise SystemExit if the requested version
|
141
|
or later cannot be installed.
|
158
|
or later cannot be installed.
|
142
|
"""
|
159
|
"""
|
|
|
160
|
+ version = _resolve_version(version)
|
143
|
to_dir = os.path.abspath(to_dir)
|
161
|
to_dir = os.path.abspath(to_dir)
|
144
|
|
162
|
|
145
|
# prior to importing, capture the module state for
|
163
|
# prior to importing, capture the module state for
|
|
@@ -189,6 +207,11 @@ def _conflict_bail(VC_err, version): |
|
@@ -189,6 +207,11 @@ def _conflict_bail(VC_err, version): |
189
|
|
207
|
|
190
|
|
208
|
|
191
|
def _unload_pkg_resources():
|
209
|
def _unload_pkg_resources():
|
|
|
210
|
+ sys.meta_path = [
|
|
|
211
|
+ importer
|
|
|
212
|
+ for importer in sys.meta_path
|
|
|
213
|
+ if importer.__class__.__module__ != 'pkg_resources.extern'
|
|
|
214
|
+ ]
|
192
|
del_modules = [
|
215
|
del_modules = [
|
193
|
name for name in sys.modules
|
216
|
name for name in sys.modules
|
194
|
if name.startswith('pkg_resources')
|
217
|
if name.startswith('pkg_resources')
|
|
@@ -222,8 +245,8 @@ def download_file_powershell(url, target): |
|
@@ -222,8 +245,8 @@ def download_file_powershell(url, target): |
222
|
ps_cmd = (
|
245
|
ps_cmd = (
|
223
|
"[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
|
246
|
"[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
|
224
|
"[System.Net.CredentialCache]::DefaultCredentials; "
|
247
|
"[System.Net.CredentialCache]::DefaultCredentials; "
|
225
|
- "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)"
|
|
|
226
|
- % vars()
|
248
|
+ '(new-object System.Net.WebClient).DownloadFile("%(url)s", "%(target)s")'
|
|
|
249
|
+ % locals()
|
227
|
)
|
250
|
)
|
228
|
cmd = [
|
251
|
cmd = [
|
229
|
'powershell',
|
252
|
'powershell',
|
|
@@ -248,7 +271,7 @@ download_file_powershell.viable = has_powershell |
|
@@ -248,7 +271,7 @@ download_file_powershell.viable = has_powershell |
248
|
|
271
|
|
249
|
|
272
|
|
250
|
def download_file_curl(url, target):
|
273
|
def download_file_curl(url, target):
|
251
|
- cmd = ['curl', url, '--silent', '--output', target]
|
274
|
+ cmd = ['curl', url, '--location', '--silent', '--output', target]
|
252
|
_clean_check(cmd, target)
|
275
|
_clean_check(cmd, target)
|
253
|
|
276
|
|
254
|
|
277
|
|
|
@@ -321,6 +344,7 @@ def download_setuptools( |
|
@@ -321,6 +344,7 @@ def download_setuptools( |
321
|
``downloader_factory`` should be a function taking no arguments and
|
344
|
``downloader_factory`` should be a function taking no arguments and
|
322
|
returning a function for downloading a URL to a target.
|
345
|
returning a function for downloading a URL to a target.
|
323
|
"""
|
346
|
"""
|
|
|
347
|
+ version = _resolve_version(version)
|
324
|
# making sure we use the absolute path
|
348
|
# making sure we use the absolute path
|
325
|
to_dir = os.path.abspath(to_dir)
|
349
|
to_dir = os.path.abspath(to_dir)
|
326
|
zip_name = "setuptools-%s.zip" % version
|
350
|
zip_name = "setuptools-%s.zip" % version
|
|
@@ -333,6 +357,27 @@ def download_setuptools( |
|
@@ -333,6 +357,27 @@ def download_setuptools( |
333
|
return os.path.realpath(saveto)
|
357
|
return os.path.realpath(saveto)
|
334
|
|
358
|
|
335
|
|
359
|
|
|
|
360
|
+def _resolve_version(version):
|
|
|
361
|
+ """
|
|
|
362
|
+ Resolve LATEST version
|
|
|
363
|
+ """
|
|
|
364
|
+ if version is not LATEST:
|
|
|
365
|
+ return version
|
|
|
366
|
+
|
|
|
367
|
+ meta_url = urljoin(DEFAULT_URL, '/pypi/setuptools/json')
|
|
|
368
|
+ resp = urlopen(meta_url)
|
|
|
369
|
+ with contextlib.closing(resp):
|
|
|
370
|
+ try:
|
|
|
371
|
+ charset = resp.info().get_content_charset()
|
|
|
372
|
+ except Exception:
|
|
|
373
|
+ # Python 2 compat; assume UTF-8
|
|
|
374
|
+ charset = 'UTF-8'
|
|
|
375
|
+ reader = codecs.getreader(charset)
|
|
|
376
|
+ doc = json.load(reader(resp))
|
|
|
377
|
+
|
|
|
378
|
+ return str(doc['info']['version'])
|
|
|
379
|
+
|
|
|
380
|
+
|
336
|
def _build_install_args(options):
|
381
|
def _build_install_args(options):
|
337
|
"""
|
382
|
"""
|
338
|
Build the arguments to 'python setup.py install' on the setuptools package.
|
383
|
Build the arguments to 'python setup.py install' on the setuptools package.
|
|
@@ -347,7 +392,7 @@ def _parse_args(): |
|
@@ -347,7 +392,7 @@ def _parse_args(): |
347
|
parser = optparse.OptionParser()
|
392
|
parser = optparse.OptionParser()
|
348
|
parser.add_option(
|
393
|
parser.add_option(
|
349
|
'--user', dest='user_install', action='store_true', default=False,
|
394
|
'--user', dest='user_install', action='store_true', default=False,
|
350
|
- help='install in user site package (requires Python 2.6 or later)')
|
395
|
+ help='install in user site package')
|
351
|
parser.add_option(
|
396
|
parser.add_option(
|
352
|
'--download-base', dest='download_base', metavar="URL",
|
397
|
'--download-base', dest='download_base', metavar="URL",
|
353
|
default=DEFAULT_URL,
|
398
|
default=DEFAULT_URL,
|
|
@@ -362,9 +407,9 @@ def _parse_args(): |
|
@@ -362,9 +407,9 @@ def _parse_args(): |
362
|
default=DEFAULT_VERSION,
|
407
|
default=DEFAULT_VERSION,
|
363
|
)
|
408
|
)
|
364
|
parser.add_option(
|
409
|
parser.add_option(
|
365
|
- '--to-dir',
|
|
|
366
|
- help="Directory to save (and re-use) package",
|
|
|
367
|
- default=DEFAULT_SAVE_DIR,
|
410
|
+ '--to-dir',
|
|
|
411
|
+ help="Directory to save (and re-use) package",
|
|
|
412
|
+ default=DEFAULT_SAVE_DIR,
|
368
|
)
|
413
|
)
|
369
|
options, args = parser.parse_args()
|
414
|
options, args = parser.parse_args()
|
370
|
# positional arguments are ignored
|
415
|
# positional arguments are ignored
|
|
@@ -372,13 +417,13 @@ def _parse_args(): |
|
@@ -372,13 +417,13 @@ def _parse_args(): |
372
|
|
417
|
|
373
|
|
418
|
|
374
|
def _download_args(options):
|
419
|
def _download_args(options):
|
375
|
- """Return args for download_setuptools function from cmdline args."""
|
|
|
376
|
- return dict(
|
|
|
377
|
- version=options.version,
|
|
|
378
|
- download_base=options.download_base,
|
|
|
379
|
- downloader_factory=options.downloader_factory,
|
|
|
380
|
- to_dir=options.to_dir,
|
|
|
381
|
- )
|
420
|
+ """Return args for download_setuptools function from cmdline args."""
|
|
|
421
|
+ return dict(
|
|
|
422
|
+ version=options.version,
|
|
|
423
|
+ download_base=options.download_base,
|
|
|
424
|
+ downloader_factory=options.downloader_factory,
|
|
|
425
|
+ to_dir=options.to_dir,
|
|
|
426
|
+ )
|
382
|
|
427
|
|
383
|
|
428
|
|
384
|
def main():
|
429
|
def main():
|