17
17
import shutil
18
18
import sys
19
19
import tempfile
20
- import tarfile
20
+ import zipfile
21
21
import optparse
22
22
import subprocess
23
23
import platform
24
24
import textwrap
25
+ import contextlib
25
26
26
27
from distutils import log
27
28
30
31
except ImportError :
31
32
USER_SITE = None
32
33
33
- DEFAULT_VERSION = "2.2 "
34
+ DEFAULT_VERSION = "3.6 "
34
35
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
35
36
36
37
def _python_cmd (* args ):
@@ -40,70 +41,71 @@ def _python_cmd(*args):
40
41
args = (sys .executable ,) + args
41
42
return subprocess .call (args ) == 0
42
43
43
- def _install (tarball , install_args = ()):
44
- # extracting the tarball
45
- tmpdir = tempfile .mkdtemp ()
46
- log .warn ('Extracting in %s' , tmpdir )
47
- old_wd = os .getcwd ()
48
- try :
49
- os .chdir (tmpdir )
50
- tar = tarfile .open (tarball )
51
- _extractall (tar )
52
- tar .close ()
53
-
54
- # going in the directory
55
- subdir = os .path .join (tmpdir , os .listdir (tmpdir )[0 ])
56
- os .chdir (subdir )
57
- log .warn ('Now working in %s' , subdir )
58
44
45
+ def _install (archive_filename , install_args = ()):
46
+ with archive_context (archive_filename ):
59
47
# installing
60
48
log .warn ('Installing Setuptools' )
61
49
if not _python_cmd ('setup.py' , 'install' , * install_args ):
62
50
log .warn ('Something went wrong during the installation.' )
63
51
log .warn ('See the error message above.' )
64
52
# exitcode will be 2
65
53
return 2
66
- finally :
67
- os .chdir (old_wd )
68
- shutil .rmtree (tmpdir )
69
54
70
55
71
- def _build_egg (egg , tarball , to_dir ):
72
- # extracting the tarball
56
+ def _build_egg (egg , archive_filename , to_dir ):
57
+ with archive_context (archive_filename ):
58
+ # building an egg
59
+ log .warn ('Building a Setuptools egg in %s' , to_dir )
60
+ _python_cmd ('setup.py' , '-q' , 'bdist_egg' , '--dist-dir' , to_dir )
61
+ # returning the result
62
+ log .warn (egg )
63
+ if not os .path .exists (egg ):
64
+ raise IOError ('Could not build the egg.' )
65
+
66
+
67
+ def get_zip_class ():
68
+ """
69
+ Supplement ZipFile class to support context manager for Python 2.6
70
+ """
71
+ class ContextualZipFile (zipfile .ZipFile ):
72
+ def __enter__ (self ):
73
+ return self
74
+ def __exit__ (self , type , value , traceback ):
75
+ self .close
76
+ return zipfile .ZipFile if hasattr (zipfile .ZipFile , '__exit__' ) else \
77
+ ContextualZipFile
78
+
79
+
80
+ @contextlib .contextmanager
81
+ def archive_context (filename ):
82
+ # extracting the archive
73
83
tmpdir = tempfile .mkdtemp ()
74
84
log .warn ('Extracting in %s' , tmpdir )
75
85
old_wd = os .getcwd ()
76
86
try :
77
87
os .chdir (tmpdir )
78
- tar = tarfile .open (tarball )
79
- _extractall (tar )
80
- tar .close ()
88
+ with get_zip_class ()(filename ) as archive :
89
+ archive .extractall ()
81
90
82
91
# going in the directory
83
92
subdir = os .path .join (tmpdir , os .listdir (tmpdir )[0 ])
84
93
os .chdir (subdir )
85
94
log .warn ('Now working in %s' , subdir )
86
-
87
- # building an egg
88
- log .warn ('Building a Setuptools egg in %s' , to_dir )
89
- _python_cmd ('setup.py' , '-q' , 'bdist_egg' , '--dist-dir' , to_dir )
95
+ yield
90
96
91
97
finally :
92
98
os .chdir (old_wd )
93
99
shutil .rmtree (tmpdir )
94
- # returning the result
95
- log .warn (egg )
96
- if not os .path .exists (egg ):
97
- raise IOError ('Could not build the egg.' )
98
100
99
101
100
102
def _do_download (version , download_base , to_dir , download_delay ):
101
103
egg = os .path .join (to_dir , 'setuptools-%s-py%d.%d.egg'
102
104
% (version , sys .version_info [0 ], sys .version_info [1 ]))
103
105
if not os .path .exists (egg ):
104
- tarball = download_setuptools (version , download_base ,
106
+ archive = download_setuptools (version , download_base ,
105
107
to_dir , download_delay )
106
- _build_egg (egg , tarball , to_dir )
108
+ _build_egg (egg , archive , to_dir )
107
109
sys .path .insert (0 , egg )
108
110
109
111
# Remove previously-imported pkg_resources if present (see
@@ -116,7 +118,7 @@ def _do_download(version, download_base, to_dir, download_delay):
116
118
117
119
118
120
def use_setuptools (version = DEFAULT_VERSION , download_base = DEFAULT_URL ,
119
- to_dir = os .curdir , download_delay = 15 ):
121
+ to_dir = os .curdir , download_delay = 15 ):
120
122
to_dir = os .path .abspath (to_dir )
121
123
rep_modules = 'pkg_resources' , 'setuptools'
122
124
imported = set (sys .modules ).intersection (rep_modules )
@@ -164,10 +166,16 @@ def download_file_powershell(url, target):
164
166
trust). Raise an exception if the command cannot complete.
165
167
"""
166
168
target = os .path .abspath (target )
169
+ ps_cmd = (
170
+ "[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
171
+ "[System.Net.CredentialCache]::DefaultCredentials; "
172
+ "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)"
173
+ % vars ()
174
+ )
167
175
cmd = [
168
176
'powershell' ,
169
177
'-Command' ,
170
- "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars () ,
178
+ ps_cmd ,
171
179
]
172
180
_clean_check (cmd , target )
173
181
@@ -179,7 +187,7 @@ def has_powershell():
179
187
try :
180
188
try :
181
189
subprocess .check_call (cmd , stdout = devnull , stderr = devnull )
182
- except :
190
+ except Exception :
183
191
return False
184
192
finally :
185
193
devnull .close ()
@@ -197,7 +205,7 @@ def has_curl():
197
205
try :
198
206
try :
199
207
subprocess .check_call (cmd , stdout = devnull , stderr = devnull )
200
- except :
208
+ except Exception :
201
209
return False
202
210
finally :
203
211
devnull .close ()
@@ -215,7 +223,7 @@ def has_wget():
215
223
try :
216
224
try :
217
225
subprocess .check_call (cmd , stdout = devnull , stderr = devnull )
218
- except :
226
+ except Exception :
219
227
return False
220
228
finally :
221
229
devnull .close ()
@@ -261,9 +269,9 @@ def get_best_downloader():
261
269
return dl
262
270
263
271
def download_setuptools (version = DEFAULT_VERSION , download_base = DEFAULT_URL ,
264
- to_dir = os .curdir , delay = 15 ,
265
- downloader_factory = get_best_downloader ):
266
- """ Download setuptools from a specified location and return its filename
272
+ to_dir = os .curdir , delay = 15 , downloader_factory = get_best_downloader ):
273
+ """
274
+ Download setuptools from a specified location and return its filename
267
275
268
276
`version` should be a valid setuptools version number that is available
269
277
as an egg for download under the `download_base` URL (which should end
@@ -276,56 +284,15 @@ def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
276
284
"""
277
285
# making sure we use the absolute path
278
286
to_dir = os .path .abspath (to_dir )
279
- tgz_name = "setuptools-%s.tar.gz " % version
280
- url = download_base + tgz_name
281
- saveto = os .path .join (to_dir , tgz_name )
287
+ zip_name = "setuptools-%s.zip " % version
288
+ url = download_base + zip_name
289
+ saveto = os .path .join (to_dir , zip_name )
282
290
if not os .path .exists (saveto ): # Avoid repeated downloads
283
291
log .warn ("Downloading %s" , url )
284
292
downloader = downloader_factory ()
285
293
downloader (url , saveto )
286
294
return os .path .realpath (saveto )
287
295
288
-
289
- def _extractall (self , path = "." , members = None ):
290
- """Extract all members from the archive to the current working
291
- directory and set owner, modification time and permissions on
292
- directories afterwards. `path' specifies a different directory
293
- to extract to. `members' is optional and must be a subset of the
294
- list returned by getmembers().
295
- """
296
- import copy
297
- import operator
298
- from tarfile import ExtractError
299
- directories = []
300
-
301
- if members is None :
302
- members = self
303
-
304
- for tarinfo in members :
305
- if tarinfo .isdir ():
306
- # Extract directories with a safe mode.
307
- directories .append (tarinfo )
308
- tarinfo = copy .copy (tarinfo )
309
- tarinfo .mode = 448 # decimal for oct 0700
310
- self .extract (tarinfo , path )
311
-
312
- # Reverse sort directories.
313
- directories .sort (key = operator .attrgetter ('name' ), reverse = True )
314
-
315
- # Set correct owner, mtime and filemode on directories.
316
- for tarinfo in directories :
317
- dirpath = os .path .join (path , tarinfo .name )
318
- try :
319
- self .chown (tarinfo , dirpath )
320
- self .utime (tarinfo , dirpath )
321
- self .chmod (tarinfo , dirpath )
322
- except ExtractError as e :
323
- if self .errorlevel > 1 :
324
- raise
325
- else :
326
- self ._dbg (1 , "tarfile: %s" % e )
327
-
328
-
329
296
def _build_install_args (options ):
330
297
"""
331
298
Build the arguments to 'python setup.py install' on the setuptools package
@@ -349,16 +316,23 @@ def _parse_args():
349
316
const = lambda : download_file_insecure , default = get_best_downloader ,
350
317
help = 'Use internal, non-validating downloader'
351
318
)
319
+ parser .add_option (
320
+ '--version' , help = "Specify which version to download" ,
321
+ default = DEFAULT_VERSION ,
322
+ )
352
323
options , args = parser .parse_args ()
353
324
# positional arguments are ignored
354
325
return options
355
326
356
- def main (version = DEFAULT_VERSION ):
327
+ def main ():
357
328
"""Install or upgrade setuptools and EasyInstall"""
358
329
options = _parse_args ()
359
- tarball = download_setuptools (download_base = options .download_base ,
360
- downloader_factory = options .downloader_factory )
361
- return _install (tarball , _build_install_args (options ))
330
+ archive = download_setuptools (
331
+ version = options .version ,
332
+ download_base = options .download_base ,
333
+ downloader_factory = options .downloader_factory ,
334
+ )
335
+ return _install (archive , _build_install_args (options ))
362
336
363
337
if __name__ == '__main__' :
364
338
sys .exit (main ())
0 commit comments