1717import shutil
1818import sys
1919import tempfile
20- import tarfile
20+ import zipfile
2121import optparse
2222import subprocess
2323import platform
2424import textwrap
25+ import contextlib
2526
2627from distutils import log
2728
3031except ImportError :
3132 USER_SITE = None
3233
33- DEFAULT_VERSION = "2.2 "
34+ DEFAULT_VERSION = "3.6 "
3435DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
3536
3637def _python_cmd (* args ):
@@ -40,70 +41,71 @@ def _python_cmd(*args):
4041 args = (sys .executable ,) + args
4142 return subprocess .call (args ) == 0
4243
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 )
5844
45+ def _install (archive_filename , install_args = ()):
46+ with archive_context (archive_filename ):
5947 # installing
6048 log .warn ('Installing Setuptools' )
6149 if not _python_cmd ('setup.py' , 'install' , * install_args ):
6250 log .warn ('Something went wrong during the installation.' )
6351 log .warn ('See the error message above.' )
6452 # exitcode will be 2
6553 return 2
66- finally :
67- os .chdir (old_wd )
68- shutil .rmtree (tmpdir )
6954
7055
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
7383 tmpdir = tempfile .mkdtemp ()
7484 log .warn ('Extracting in %s' , tmpdir )
7585 old_wd = os .getcwd ()
7686 try :
7787 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 ()
8190
8291 # going in the directory
8392 subdir = os .path .join (tmpdir , os .listdir (tmpdir )[0 ])
8493 os .chdir (subdir )
8594 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
9096
9197 finally :
9298 os .chdir (old_wd )
9399 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.' )
98100
99101
100102def _do_download (version , download_base , to_dir , download_delay ):
101103 egg = os .path .join (to_dir , 'setuptools-%s-py%d.%d.egg'
102104 % (version , sys .version_info [0 ], sys .version_info [1 ]))
103105 if not os .path .exists (egg ):
104- tarball = download_setuptools (version , download_base ,
106+ archive = download_setuptools (version , download_base ,
105107 to_dir , download_delay )
106- _build_egg (egg , tarball , to_dir )
108+ _build_egg (egg , archive , to_dir )
107109 sys .path .insert (0 , egg )
108110
109111 # Remove previously-imported pkg_resources if present (see
@@ -116,7 +118,7 @@ def _do_download(version, download_base, to_dir, download_delay):
116118
117119
118120def 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 ):
120122 to_dir = os .path .abspath (to_dir )
121123 rep_modules = 'pkg_resources' , 'setuptools'
122124 imported = set (sys .modules ).intersection (rep_modules )
@@ -164,10 +166,16 @@ def download_file_powershell(url, target):
164166 trust). Raise an exception if the command cannot complete.
165167 """
166168 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+ )
167175 cmd = [
168176 'powershell' ,
169177 '-Command' ,
170- "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars () ,
178+ ps_cmd ,
171179 ]
172180 _clean_check (cmd , target )
173181
@@ -179,7 +187,7 @@ def has_powershell():
179187 try :
180188 try :
181189 subprocess .check_call (cmd , stdout = devnull , stderr = devnull )
182- except :
190+ except Exception :
183191 return False
184192 finally :
185193 devnull .close ()
@@ -197,7 +205,7 @@ def has_curl():
197205 try :
198206 try :
199207 subprocess .check_call (cmd , stdout = devnull , stderr = devnull )
200- except :
208+ except Exception :
201209 return False
202210 finally :
203211 devnull .close ()
@@ -215,7 +223,7 @@ def has_wget():
215223 try :
216224 try :
217225 subprocess .check_call (cmd , stdout = devnull , stderr = devnull )
218- except :
226+ except Exception :
219227 return False
220228 finally :
221229 devnull .close ()
@@ -261,9 +269,9 @@ def get_best_downloader():
261269 return dl
262270
263271def 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
267275
268276 `version` should be a valid setuptools version number that is available
269277 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,
276284 """
277285 # making sure we use the absolute path
278286 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 )
282290 if not os .path .exists (saveto ): # Avoid repeated downloads
283291 log .warn ("Downloading %s" , url )
284292 downloader = downloader_factory ()
285293 downloader (url , saveto )
286294 return os .path .realpath (saveto )
287295
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-
329296def _build_install_args (options ):
330297 """
331298 Build the arguments to 'python setup.py install' on the setuptools package
@@ -349,16 +316,23 @@ def _parse_args():
349316 const = lambda : download_file_insecure , default = get_best_downloader ,
350317 help = 'Use internal, non-validating downloader'
351318 )
319+ parser .add_option (
320+ '--version' , help = "Specify which version to download" ,
321+ default = DEFAULT_VERSION ,
322+ )
352323 options , args = parser .parse_args ()
353324 # positional arguments are ignored
354325 return options
355326
356- def main (version = DEFAULT_VERSION ):
327+ def main ():
357328 """Install or upgrade setuptools and EasyInstall"""
358329 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 ))
362336
363337if __name__ == '__main__' :
364338 sys .exit (main ())
0 commit comments