Mon, 09 May 2011 15:15:46 +0100
Improving setup script by removing dependence on setuptools
distribute_setup.py | file | annotate | diff | comparison | revisions | |
setup.py | file | annotate | diff | comparison | revisions |
1.1 --- a/distribute_setup.py Sat Sep 04 19:50:16 2010 +0000 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,477 +0,0 @@ 1.4 -#!python 1.5 -"""Bootstrap distribute installation 1.6 - 1.7 -If you want to use setuptools in your package's setup.py, just include this 1.8 -file in the same directory with it, and add this to the top of your setup.py:: 1.9 - 1.10 - from distribute_setup import use_setuptools 1.11 - use_setuptools() 1.12 - 1.13 -If you want to require a specific version of setuptools, set a download 1.14 -mirror, or use an alternate download directory, you can do so by supplying 1.15 -the appropriate options to ``use_setuptools()``. 1.16 - 1.17 -This file can also be run as a script to install or upgrade setuptools. 1.18 -""" 1.19 -import os 1.20 -import sys 1.21 -import time 1.22 -import fnmatch 1.23 -import tempfile 1.24 -import tarfile 1.25 -from distutils import log 1.26 - 1.27 -try: 1.28 - from site import USER_SITE 1.29 -except ImportError: 1.30 - USER_SITE = None 1.31 - 1.32 -try: 1.33 - import subprocess 1.34 - 1.35 - def _python_cmd(*args): 1.36 - args = (sys.executable,) + args 1.37 - return subprocess.call(args) == 0 1.38 - 1.39 -except ImportError: 1.40 - # will be used for python 2.3 1.41 - def _python_cmd(*args): 1.42 - args = (sys.executable,) + args 1.43 - # quoting arguments if windows 1.44 - if sys.platform == 'win32': 1.45 - def quote(arg): 1.46 - if ' ' in arg: 1.47 - return '"%s"' % arg 1.48 - return arg 1.49 - args = [quote(arg) for arg in args] 1.50 - return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 1.51 - 1.52 -DEFAULT_VERSION = "0.6.10" 1.53 -DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" 1.54 -SETUPTOOLS_FAKED_VERSION = "0.6c11" 1.55 - 1.56 -SETUPTOOLS_PKG_INFO = """\ 1.57 -Metadata-Version: 1.0 1.58 -Name: setuptools 1.59 -Version: %s 1.60 -Summary: xxxx 1.61 -Home-page: xxx 1.62 -Author: xxx 1.63 -Author-email: xxx 1.64 -License: xxx 1.65 -Description: xxx 1.66 -""" % SETUPTOOLS_FAKED_VERSION 1.67 - 1.68 - 1.69 -def _install(tarball): 1.70 - # extracting the tarball 1.71 - tmpdir = tempfile.mkdtemp() 1.72 - log.warn('Extracting in %s', tmpdir) 1.73 - old_wd = os.getcwd() 1.74 - try: 1.75 - os.chdir(tmpdir) 1.76 - tar = tarfile.open(tarball) 1.77 - _extractall(tar) 1.78 - tar.close() 1.79 - 1.80 - # going in the directory 1.81 - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 1.82 - os.chdir(subdir) 1.83 - log.warn('Now working in %s', subdir) 1.84 - 1.85 - # installing 1.86 - log.warn('Installing Distribute') 1.87 - if not _python_cmd('setup.py', 'install'): 1.88 - log.warn('Something went wrong during the installation.') 1.89 - log.warn('See the error message above.') 1.90 - finally: 1.91 - os.chdir(old_wd) 1.92 - 1.93 - 1.94 -def _build_egg(egg, tarball, to_dir): 1.95 - # extracting the tarball 1.96 - tmpdir = tempfile.mkdtemp() 1.97 - log.warn('Extracting in %s', tmpdir) 1.98 - old_wd = os.getcwd() 1.99 - try: 1.100 - os.chdir(tmpdir) 1.101 - tar = tarfile.open(tarball) 1.102 - _extractall(tar) 1.103 - tar.close() 1.104 - 1.105 - # going in the directory 1.106 - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 1.107 - os.chdir(subdir) 1.108 - log.warn('Now working in %s', subdir) 1.109 - 1.110 - # building an egg 1.111 - log.warn('Building a Distribute egg in %s', to_dir) 1.112 - _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) 1.113 - 1.114 - finally: 1.115 - os.chdir(old_wd) 1.116 - # returning the result 1.117 - log.warn(egg) 1.118 - if not os.path.exists(egg): 1.119 - raise IOError('Could not build the egg.') 1.120 - 1.121 - 1.122 -def _do_download(version, download_base, to_dir, download_delay): 1.123 - egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' 1.124 - % (version, sys.version_info[0], sys.version_info[1])) 1.125 - if not os.path.exists(egg): 1.126 - tarball = download_setuptools(version, download_base, 1.127 - to_dir, download_delay) 1.128 - _build_egg(egg, tarball, to_dir) 1.129 - sys.path.insert(0, egg) 1.130 - import setuptools 1.131 - setuptools.bootstrap_install_from = egg 1.132 - 1.133 - 1.134 -def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 1.135 - to_dir=os.curdir, download_delay=15, no_fake=True): 1.136 - # making sure we use the absolute path 1.137 - to_dir = os.path.abspath(to_dir) 1.138 - was_imported = 'pkg_resources' in sys.modules or \ 1.139 - 'setuptools' in sys.modules 1.140 - try: 1.141 - try: 1.142 - import pkg_resources 1.143 - if not hasattr(pkg_resources, '_distribute'): 1.144 - if not no_fake: 1.145 - _fake_setuptools() 1.146 - raise ImportError 1.147 - except ImportError: 1.148 - return _do_download(version, download_base, to_dir, download_delay) 1.149 - try: 1.150 - pkg_resources.require("distribute>="+version) 1.151 - return 1.152 - except pkg_resources.VersionConflict: 1.153 - e = sys.exc_info()[1] 1.154 - if was_imported: 1.155 - sys.stderr.write( 1.156 - "The required version of distribute (>=%s) is not available,\n" 1.157 - "and can't be installed while this script is running. Please\n" 1.158 - "install a more recent version first, using\n" 1.159 - "'easy_install -U distribute'." 1.160 - "\n\n(Currently using %r)\n" % (version, e.args[0])) 1.161 - sys.exit(2) 1.162 - else: 1.163 - del pkg_resources, sys.modules['pkg_resources'] # reload ok 1.164 - return _do_download(version, download_base, to_dir, 1.165 - download_delay) 1.166 - except pkg_resources.DistributionNotFound: 1.167 - return _do_download(version, download_base, to_dir, 1.168 - download_delay) 1.169 - finally: 1.170 - if not no_fake: 1.171 - _create_fake_setuptools_pkg_info(to_dir) 1.172 - 1.173 -def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 1.174 - to_dir=os.curdir, delay=15): 1.175 - """Download distribute from a specified location and return its filename 1.176 - 1.177 - `version` should be a valid distribute version number that is available 1.178 - as an egg for download under the `download_base` URL (which should end 1.179 - with a '/'). `to_dir` is the directory where the egg will be downloaded. 1.180 - `delay` is the number of seconds to pause before an actual download 1.181 - attempt. 1.182 - """ 1.183 - # making sure we use the absolute path 1.184 - to_dir = os.path.abspath(to_dir) 1.185 - try: 1.186 - from urllib.request import urlopen 1.187 - except ImportError: 1.188 - from urllib2 import urlopen 1.189 - tgz_name = "distribute-%s.tar.gz" % version 1.190 - url = download_base + tgz_name 1.191 - saveto = os.path.join(to_dir, tgz_name) 1.192 - src = dst = None 1.193 - if not os.path.exists(saveto): # Avoid repeated downloads 1.194 - try: 1.195 - log.warn("Downloading %s", url) 1.196 - src = urlopen(url) 1.197 - # Read/write all in one block, so we don't create a corrupt file 1.198 - # if the download is interrupted. 1.199 - data = src.read() 1.200 - dst = open(saveto, "wb") 1.201 - dst.write(data) 1.202 - finally: 1.203 - if src: 1.204 - src.close() 1.205 - if dst: 1.206 - dst.close() 1.207 - return os.path.realpath(saveto) 1.208 - 1.209 - 1.210 -def _patch_file(path, content): 1.211 - """Will backup the file then patch it""" 1.212 - existing_content = open(path).read() 1.213 - if existing_content == content: 1.214 - # already patched 1.215 - log.warn('Already patched.') 1.216 - return False 1.217 - log.warn('Patching...') 1.218 - _rename_path(path) 1.219 - f = open(path, 'w') 1.220 - try: 1.221 - f.write(content) 1.222 - finally: 1.223 - f.close() 1.224 - return True 1.225 - 1.226 - 1.227 -def _same_content(path, content): 1.228 - return open(path).read() == content 1.229 - 1.230 -def _no_sandbox(function): 1.231 - def __no_sandbox(*args, **kw): 1.232 - try: 1.233 - from setuptools.sandbox import DirectorySandbox 1.234 - def violation(*args): 1.235 - pass 1.236 - DirectorySandbox._old = DirectorySandbox._violation 1.237 - DirectorySandbox._violation = violation 1.238 - patched = True 1.239 - except ImportError: 1.240 - patched = False 1.241 - 1.242 - try: 1.243 - return function(*args, **kw) 1.244 - finally: 1.245 - if patched: 1.246 - DirectorySandbox._violation = DirectorySandbox._old 1.247 - del DirectorySandbox._old 1.248 - 1.249 - return __no_sandbox 1.250 - 1.251 -@_no_sandbox 1.252 -def _rename_path(path): 1.253 - new_name = path + '.OLD.%s' % time.time() 1.254 - log.warn('Renaming %s into %s', path, new_name) 1.255 - os.rename(path, new_name) 1.256 - return new_name 1.257 - 1.258 -def _remove_flat_installation(placeholder): 1.259 - if not os.path.isdir(placeholder): 1.260 - log.warn('Unkown installation at %s', placeholder) 1.261 - return False 1.262 - found = False 1.263 - for file in os.listdir(placeholder): 1.264 - if fnmatch.fnmatch(file, 'setuptools*.egg-info'): 1.265 - found = True 1.266 - break 1.267 - if not found: 1.268 - log.warn('Could not locate setuptools*.egg-info') 1.269 - return 1.270 - 1.271 - log.warn('Removing elements out of the way...') 1.272 - pkg_info = os.path.join(placeholder, file) 1.273 - if os.path.isdir(pkg_info): 1.274 - patched = _patch_egg_dir(pkg_info) 1.275 - else: 1.276 - patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) 1.277 - 1.278 - if not patched: 1.279 - log.warn('%s already patched.', pkg_info) 1.280 - return False 1.281 - # now let's move the files out of the way 1.282 - for element in ('setuptools', 'pkg_resources.py', 'site.py'): 1.283 - element = os.path.join(placeholder, element) 1.284 - if os.path.exists(element): 1.285 - _rename_path(element) 1.286 - else: 1.287 - log.warn('Could not find the %s element of the ' 1.288 - 'Setuptools distribution', element) 1.289 - return True 1.290 - 1.291 - 1.292 -def _after_install(dist): 1.293 - log.warn('After install bootstrap.') 1.294 - placeholder = dist.get_command_obj('install').install_purelib 1.295 - _create_fake_setuptools_pkg_info(placeholder) 1.296 - 1.297 -@_no_sandbox 1.298 -def _create_fake_setuptools_pkg_info(placeholder): 1.299 - if not placeholder or not os.path.exists(placeholder): 1.300 - log.warn('Could not find the install location') 1.301 - return 1.302 - pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) 1.303 - setuptools_file = 'setuptools-%s-py%s.egg-info' % \ 1.304 - (SETUPTOOLS_FAKED_VERSION, pyver) 1.305 - pkg_info = os.path.join(placeholder, setuptools_file) 1.306 - if os.path.exists(pkg_info): 1.307 - log.warn('%s already exists', pkg_info) 1.308 - return 1.309 - 1.310 - log.warn('Creating %s', pkg_info) 1.311 - f = open(pkg_info, 'w') 1.312 - try: 1.313 - f.write(SETUPTOOLS_PKG_INFO) 1.314 - finally: 1.315 - f.close() 1.316 - 1.317 - pth_file = os.path.join(placeholder, 'setuptools.pth') 1.318 - log.warn('Creating %s', pth_file) 1.319 - f = open(pth_file, 'w') 1.320 - try: 1.321 - f.write(os.path.join(os.curdir, setuptools_file)) 1.322 - finally: 1.323 - f.close() 1.324 - 1.325 -def _patch_egg_dir(path): 1.326 - # let's check if it's already patched 1.327 - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 1.328 - if os.path.exists(pkg_info): 1.329 - if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): 1.330 - log.warn('%s already patched.', pkg_info) 1.331 - return False 1.332 - _rename_path(path) 1.333 - os.mkdir(path) 1.334 - os.mkdir(os.path.join(path, 'EGG-INFO')) 1.335 - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 1.336 - f = open(pkg_info, 'w') 1.337 - try: 1.338 - f.write(SETUPTOOLS_PKG_INFO) 1.339 - finally: 1.340 - f.close() 1.341 - return True 1.342 - 1.343 - 1.344 -def _before_install(): 1.345 - log.warn('Before install bootstrap.') 1.346 - _fake_setuptools() 1.347 - 1.348 - 1.349 -def _under_prefix(location): 1.350 - if 'install' not in sys.argv: 1.351 - return True 1.352 - args = sys.argv[sys.argv.index('install')+1:] 1.353 - for index, arg in enumerate(args): 1.354 - for option in ('--root', '--prefix'): 1.355 - if arg.startswith('%s=' % option): 1.356 - top_dir = arg.split('root=')[-1] 1.357 - return location.startswith(top_dir) 1.358 - elif arg == option: 1.359 - if len(args) > index: 1.360 - top_dir = args[index+1] 1.361 - return location.startswith(top_dir) 1.362 - elif option == '--user' and USER_SITE is not None: 1.363 - return location.startswith(USER_SITE) 1.364 - return True 1.365 - 1.366 - 1.367 -def _fake_setuptools(): 1.368 - log.warn('Scanning installed packages') 1.369 - try: 1.370 - import pkg_resources 1.371 - except ImportError: 1.372 - # we're cool 1.373 - log.warn('Setuptools or Distribute does not seem to be installed.') 1.374 - return 1.375 - ws = pkg_resources.working_set 1.376 - try: 1.377 - setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', 1.378 - replacement=False)) 1.379 - except TypeError: 1.380 - # old distribute API 1.381 - setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) 1.382 - 1.383 - if setuptools_dist is None: 1.384 - log.warn('No setuptools distribution found') 1.385 - return 1.386 - # detecting if it was already faked 1.387 - setuptools_location = setuptools_dist.location 1.388 - log.warn('Setuptools installation detected at %s', setuptools_location) 1.389 - 1.390 - # if --root or --preix was provided, and if 1.391 - # setuptools is not located in them, we don't patch it 1.392 - if not _under_prefix(setuptools_location): 1.393 - log.warn('Not patching, --root or --prefix is installing Distribute' 1.394 - ' in another location') 1.395 - return 1.396 - 1.397 - # let's see if its an egg 1.398 - if not setuptools_location.endswith('.egg'): 1.399 - log.warn('Non-egg installation') 1.400 - res = _remove_flat_installation(setuptools_location) 1.401 - if not res: 1.402 - return 1.403 - else: 1.404 - log.warn('Egg installation') 1.405 - pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') 1.406 - if (os.path.exists(pkg_info) and 1.407 - _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): 1.408 - log.warn('Already patched.') 1.409 - return 1.410 - log.warn('Patching...') 1.411 - # let's create a fake egg replacing setuptools one 1.412 - res = _patch_egg_dir(setuptools_location) 1.413 - if not res: 1.414 - return 1.415 - log.warn('Patched done.') 1.416 - _relaunch() 1.417 - 1.418 - 1.419 -def _relaunch(): 1.420 - log.warn('Relaunching...') 1.421 - # we have to relaunch the process 1.422 - args = [sys.executable] + sys.argv 1.423 - sys.exit(subprocess.call(args)) 1.424 - 1.425 - 1.426 -def _extractall(self, path=".", members=None): 1.427 - """Extract all members from the archive to the current working 1.428 - directory and set owner, modification time and permissions on 1.429 - directories afterwards. `path' specifies a different directory 1.430 - to extract to. `members' is optional and must be a subset of the 1.431 - list returned by getmembers(). 1.432 - """ 1.433 - import copy 1.434 - import operator 1.435 - from tarfile import ExtractError 1.436 - directories = [] 1.437 - 1.438 - if members is None: 1.439 - members = self 1.440 - 1.441 - for tarinfo in members: 1.442 - if tarinfo.isdir(): 1.443 - # Extract directories with a safe mode. 1.444 - directories.append(tarinfo) 1.445 - tarinfo = copy.copy(tarinfo) 1.446 - tarinfo.mode = 448 # decimal for oct 0700 1.447 - self.extract(tarinfo, path) 1.448 - 1.449 - # Reverse sort directories. 1.450 - if sys.version_info < (2, 4): 1.451 - def sorter(dir1, dir2): 1.452 - return cmp(dir1.name, dir2.name) 1.453 - directories.sort(sorter) 1.454 - directories.reverse() 1.455 - else: 1.456 - directories.sort(key=operator.attrgetter('name'), reverse=True) 1.457 - 1.458 - # Set correct owner, mtime and filemode on directories. 1.459 - for tarinfo in directories: 1.460 - dirpath = os.path.join(path, tarinfo.name) 1.461 - try: 1.462 - self.chown(tarinfo, dirpath) 1.463 - self.utime(tarinfo, dirpath) 1.464 - self.chmod(tarinfo, dirpath) 1.465 - except ExtractError: 1.466 - e = sys.exc_info()[1] 1.467 - if self.errorlevel > 1: 1.468 - raise 1.469 - else: 1.470 - self._dbg(1, "tarfile: %s" % e) 1.471 - 1.472 - 1.473 -def main(argv, version=DEFAULT_VERSION): 1.474 - """Install or upgrade setuptools and EasyInstall""" 1.475 - tarball = download_setuptools() 1.476 - _install(tarball) 1.477 - 1.478 - 1.479 -if __name__ == '__main__': 1.480 - main(sys.argv[1:])
2.1 --- a/setup.py Sat Sep 04 19:50:16 2010 +0000 2.2 +++ b/setup.py Mon May 09 15:15:46 2011 +0100 2.3 @@ -17,16 +17,12 @@ 2.4 """ 2.5 2.6 ## Get setuptools stuff 2.7 -#from distutils.core import setup 2.8 -# from ez_setup import use_setuptools 2.9 -from distribute_setup import use_setuptools 2.10 -use_setuptools() 2.11 -from setuptools import setup 2.12 +from distutils.core import setup 2.13 2.14 2.15 ## Setup definition 2.16 setup(name = 'emin', 2.17 - version = "0.3.1", 2.18 + version = "0.3.2", 2.19 scripts = ['emin'], 2.20 author = 'Andy Buckley', 2.21 author_email = 'andy@insectnation.org',