Skip to content

Commit fbb6ce1

Browse files
committed
Update ez_setup to that for the latest version of setuptools, 2.0
1 parent ae38cc9 commit fbb6ce1

File tree

1 file changed

+139
-21
lines changed

1 file changed

+139
-21
lines changed

ez_setup.py

+139-21
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import tarfile
2121
import optparse
2222
import subprocess
23+
import platform
2324

2425
from distutils import log
2526

@@ -28,13 +29,22 @@
2829
except ImportError:
2930
USER_SITE = None
3031

31-
DEFAULT_VERSION = "0.9.8"
32+
DEFAULT_VERSION = "1.4.2"
3233
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
3334

3435
def _python_cmd(*args):
3536
args = (sys.executable,) + args
3637
return subprocess.call(args) == 0
3738

39+
def _check_call_py24(cmd, *args, **kwargs):
40+
res = subprocess.call(cmd, *args, **kwargs)
41+
class CalledProcessError(Exception):
42+
pass
43+
if not res == 0:
44+
msg = "Command '%s' return non-zero exit status %d" % (cmd, res)
45+
raise CalledProcessError(msg)
46+
vars(subprocess).setdefault('check_call', _check_call_py24)
47+
3848
def _install(tarball, install_args=()):
3949
# extracting the tarball
4050
tmpdir = tempfile.mkdtemp()
@@ -141,41 +151,143 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
141151
return _do_download(version, download_base, to_dir,
142152
download_delay)
143153

154+
def _clean_check(cmd, target):
155+
"""
156+
Run the command to download target. If the command fails, clean up before
157+
re-raising the error.
158+
"""
159+
try:
160+
subprocess.check_call(cmd)
161+
except subprocess.CalledProcessError:
162+
if os.access(target, os.F_OK):
163+
os.unlink(target)
164+
raise
165+
166+
def download_file_powershell(url, target):
167+
"""
168+
Download the file at url to target using Powershell (which will validate
169+
trust). Raise an exception if the command cannot complete.
170+
"""
171+
target = os.path.abspath(target)
172+
cmd = [
173+
'powershell',
174+
'-Command',
175+
"(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(),
176+
]
177+
_clean_check(cmd, target)
178+
179+
def has_powershell():
180+
if platform.system() != 'Windows':
181+
return False
182+
cmd = ['powershell', '-Command', 'echo test']
183+
devnull = open(os.path.devnull, 'wb')
184+
try:
185+
try:
186+
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
187+
except:
188+
return False
189+
finally:
190+
devnull.close()
191+
return True
192+
193+
download_file_powershell.viable = has_powershell
194+
195+
def download_file_curl(url, target):
196+
cmd = ['curl', url, '--silent', '--output', target]
197+
_clean_check(cmd, target)
198+
199+
def has_curl():
200+
cmd = ['curl', '--version']
201+
devnull = open(os.path.devnull, 'wb')
202+
try:
203+
try:
204+
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
205+
except:
206+
return False
207+
finally:
208+
devnull.close()
209+
return True
210+
211+
download_file_curl.viable = has_curl
212+
213+
def download_file_wget(url, target):
214+
cmd = ['wget', url, '--quiet', '--output-document', target]
215+
_clean_check(cmd, target)
216+
217+
def has_wget():
218+
cmd = ['wget', '--version']
219+
devnull = open(os.path.devnull, 'wb')
220+
try:
221+
try:
222+
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
223+
except:
224+
return False
225+
finally:
226+
devnull.close()
227+
return True
228+
229+
download_file_wget.viable = has_wget
230+
231+
def download_file_insecure(url, target):
232+
"""
233+
Use Python to download the file, even though it cannot authenticate the
234+
connection.
235+
"""
236+
try:
237+
from urllib.request import urlopen
238+
except ImportError:
239+
from urllib2 import urlopen
240+
src = dst = None
241+
try:
242+
src = urlopen(url)
243+
# Read/write all in one block, so we don't create a corrupt file
244+
# if the download is interrupted.
245+
data = src.read()
246+
dst = open(target, "wb")
247+
dst.write(data)
248+
finally:
249+
if src:
250+
src.close()
251+
if dst:
252+
dst.close()
253+
254+
download_file_insecure.viable = lambda: True
255+
256+
def get_best_downloader():
257+
downloaders = [
258+
download_file_powershell,
259+
download_file_curl,
260+
download_file_wget,
261+
download_file_insecure,
262+
]
263+
264+
for dl in downloaders:
265+
if dl.viable():
266+
return dl
144267

145268
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
146-
to_dir=os.curdir, delay=15):
269+
to_dir=os.curdir, delay=15,
270+
downloader_factory=get_best_downloader):
147271
"""Download setuptools from a specified location and return its filename
148272
149273
`version` should be a valid setuptools version number that is available
150274
as an egg for download under the `download_base` URL (which should end
151275
with a '/'). `to_dir` is the directory where the egg will be downloaded.
152276
`delay` is the number of seconds to pause before an actual download
153277
attempt.
278+
279+
``downloader_factory`` should be a function taking no arguments and
280+
returning a function for downloading a URL to a target.
154281
"""
155282
# making sure we use the absolute path
156283
to_dir = os.path.abspath(to_dir)
157-
try:
158-
from urllib.request import urlopen
159-
except ImportError:
160-
from urllib2 import urlopen
161284
tgz_name = "setuptools-%s.tar.gz" % version
162285
url = download_base + tgz_name
163286
saveto = os.path.join(to_dir, tgz_name)
164-
src = dst = None
165287
if not os.path.exists(saveto): # Avoid repeated downloads
166-
try:
167-
log.warn("Downloading %s", url)
168-
src = urlopen(url)
169-
# Read/write all in one block, so we don't create a corrupt file
170-
# if the download is interrupted.
171-
data = src.read()
172-
dst = open(saveto, "wb")
173-
dst.write(data)
174-
finally:
175-
if src:
176-
src.close()
177-
if dst:
178-
dst.close()
288+
log.warn("Downloading %s", url)
289+
downloader = downloader_factory()
290+
downloader(url, saveto)
179291
return os.path.realpath(saveto)
180292

181293

@@ -250,14 +362,20 @@ def _parse_args():
250362
'--download-base', dest='download_base', metavar="URL",
251363
default=DEFAULT_URL,
252364
help='alternative URL from where to download the setuptools package')
365+
parser.add_option(
366+
'--insecure', dest='downloader_factory', action='store_const',
367+
const=lambda: download_file_insecure, default=get_best_downloader,
368+
help='Use internal, non-validating downloader'
369+
)
253370
options, args = parser.parse_args()
254371
# positional arguments are ignored
255372
return options
256373

257374
def main(version=DEFAULT_VERSION):
258375
"""Install or upgrade setuptools and EasyInstall"""
259376
options = _parse_args()
260-
tarball = download_setuptools(download_base=options.download_base)
377+
tarball = download_setuptools(download_base=options.download_base,
378+
downloader_factory=options.downloader_factory)
261379
return _install(tarball, _build_install_args(options))
262380

263381
if __name__ == '__main__':

0 commit comments

Comments
 (0)