/ez_setup.py
Python | 272 lines | 220 code | 44 blank | 8 comment | 15 complexity | 94ce3ba3f5933e3915e999c26da9563b MD5 | raw file
1#!python 2"""Bootstrap setuptools installation 3 4If you want to use setuptools in your package's setup.py, just include this 5file in the same directory with it, and add this to the top of your setup.py:: 6 7 from ez_setup import use_setuptools 8 use_setuptools() 9 10If you want to require a specific version of setuptools, set a download 11mirror, or use an alternate download directory, you can do so by supplying 12the appropriate options to ``use_setuptools()``. 13 14This file can also be run as a script to install or upgrade setuptools. 15""" 16import sys 17DEFAULT_VERSION = "0.6c8" 18DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] 19 20md5_data = { 21 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 22 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 23 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 24 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 25 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 26 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 27 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 28 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 29 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 30 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 31 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 32 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 33 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 34 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 35 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 36 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 37 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 38 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 39 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 40 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 41 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 42 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 43 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 44 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', 45 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', 46 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', 47 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', 48 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', 49 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', 50 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', 51} 52 53import sys, os 54 55def _validate_md5(egg_name, data): 56 if egg_name in md5_data: 57 from md5 import md5 58 digest = md5(data).hexdigest() 59 if digest != md5_data[egg_name]: 60 print >>sys.stderr, ( 61 "md5 validation of %s failed! (Possible download problem?)" 62 % egg_name 63 ) 64 sys.exit(2) 65 return data 66 67 68def use_setuptools( 69 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 70 download_delay=15 71): 72 """Automatically find/download setuptools and make it available on sys.path 73 74 `version` should be a valid setuptools version number that is available 75 as an egg for download under the `download_base` URL (which should end with 76 a '/'). `to_dir` is the directory where setuptools will be downloaded, if 77 it is not already available. If `download_delay` is specified, it should 78 be the number of seconds that will be paused before initiating a download, 79 should one be required. If an older version of setuptools is installed, 80 this routine will print a message to ``sys.stderr`` and raise SystemExit in 81 an attempt to abort the calling script. 82 """ 83 was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules 84 def do_download(): 85 egg = download_setuptools(version, download_base, to_dir, download_delay) 86 sys.path.insert(0, egg) 87 import setuptools; setuptools.bootstrap_install_from = egg 88 try: 89 import pkg_resources 90 except ImportError: 91 return do_download() 92 try: 93 pkg_resources.require("setuptools>="+version); return 94 except pkg_resources.VersionConflict, e: 95 if was_imported: 96 print >>sys.stderr, ( 97 "The required version of setuptools (>=%s) is not available, and\n" 98 "can't be installed while this script is running. Please install\n" 99 " a more recent version first, using 'easy_install -U setuptools'." 100 "\n\n(Currently using %r)" 101 ) % (version, e.args[0]) 102 sys.exit(2) 103 else: 104 del pkg_resources, sys.modules['pkg_resources'] # reload ok 105 return do_download() 106 except pkg_resources.DistributionNotFound: 107 return do_download() 108 109def download_setuptools( 110 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 111 delay = 15 112): 113 """Download setuptools from a specified location and return its filename 114 115 `version` should be a valid setuptools version number that is available 116 as an egg for download under the `download_base` URL (which should end 117 with a '/'). `to_dir` is the directory where the egg will be downloaded. 118 `delay` is the number of seconds to pause before an actual download attempt. 119 """ 120 import urllib2, shutil 121 egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) 122 url = download_base + egg_name 123 saveto = os.path.join(to_dir, egg_name) 124 src = dst = None 125 if not os.path.exists(saveto): # Avoid repeated downloads 126 try: 127 from distutils import log 128 if delay: 129 log.warn(""" 130--------------------------------------------------------------------------- 131This script requires setuptools version %s to run (even to display 132help). I will attempt to download it for you (from 133%s), but 134you may need to enable firewall access for this script first. 135I will start the download in %d seconds. 136 137(Note: if this machine does not have network access, please obtain the file 138 139 %s 140 141and place it in this directory before rerunning this script.) 142---------------------------------------------------------------------------""", 143 version, download_base, delay, url 144 ); from time import sleep; sleep(delay) 145 log.warn("Downloading %s", url) 146 src = urllib2.urlopen(url) 147 # Read/write all in one block, so we don't create a corrupt file 148 # if the download is interrupted. 149 data = _validate_md5(egg_name, src.read()) 150 dst = open(saveto,"wb"); dst.write(data) 151 finally: 152 if src: src.close() 153 if dst: dst.close() 154 return os.path.realpath(saveto) 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191def main(argv, version=DEFAULT_VERSION): 192 """Install or upgrade setuptools and EasyInstall""" 193 try: 194 import setuptools 195 except ImportError: 196 egg = None 197 try: 198 egg = download_setuptools(version, delay=0) 199 sys.path.insert(0,egg) 200 from setuptools.command.easy_install import main 201 return main(list(argv)+[egg]) # we're done here 202 finally: 203 if egg and os.path.exists(egg): 204 os.unlink(egg) 205 else: 206 if setuptools.__version__ == '0.0.1': 207 print >>sys.stderr, ( 208 "You have an obsolete version of setuptools installed. Please\n" 209 "remove it from your system entirely before rerunning this script." 210 ) 211 sys.exit(2) 212 213 req = "setuptools>="+version 214 import pkg_resources 215 try: 216 pkg_resources.require(req) 217 except pkg_resources.VersionConflict: 218 try: 219 from setuptools.command.easy_install import main 220 except ImportError: 221 from easy_install import main 222 main(list(argv)+[download_setuptools(delay=0)]) 223 sys.exit(0) # try to force an exit 224 else: 225 if argv: 226 from setuptools.command.easy_install import main 227 main(argv) 228 else: 229 print "Setuptools version",version,"or greater has been installed." 230 print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' 231 232def update_md5(filenames): 233 """Update our built-in md5 registry""" 234 235 import re 236 from md5 import md5 237 238 for name in filenames: 239 base = os.path.basename(name) 240 f = open(name,'rb') 241 md5_data[base] = md5(f.read()).hexdigest() 242 f.close() 243 244 data = [" %r: %r,\n" % it for it in md5_data.items()] 245 data.sort() 246 repl = "".join(data) 247 248 import inspect 249 srcfile = inspect.getsourcefile(sys.modules[__name__]) 250 f = open(srcfile, 'rb'); src = f.read(); f.close() 251 252 match = re.search("\nmd5_data = {\n([^}]+)}", src) 253 if not match: 254 print >>sys.stderr, "Internal error!" 255 sys.exit(2) 256 257 src = src[:match.start(1)] + repl + src[match.end(1):] 258 f = open(srcfile,'w') 259 f.write(src) 260 f.close() 261 262 263if __name__=='__main__': 264 if len(sys.argv)>2 and sys.argv[1]=='--md5update': 265 update_md5(sys.argv[2:]) 266 else: 267 main(sys.argv[1:]) 268 269 270 271 272