├── .gitignore ├── Makefile ├── README.md ├── parallelize.py ├── setup.py ├── test └── test_parallelize.py └── tools └── virtualenv /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | __pycache__/ 4 | python*-*/ 5 | MANIFEST 6 | dist/ 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # Which version of python are we using? 3 | ifndef python 4 | python=3.2 5 | endif 6 | 7 | PROJECT=python-parallelize 8 | 9 | SRCDIR=. 10 | 11 | ARCHITECTURE:=$(shell uname -m) 12 | PYTHON_ENV=$(PWD)/python$(python)-$(ARCHITECTURE) 13 | PYTHON_EXE=$(PYTHON_ENV)/bin/python 14 | PIP=$(PYTHON_ENV)/bin/pip 15 | PYTHON_BUILDDIR=$(PYTHON_ENV)/build 16 | 17 | 18 | .PHONY: all 19 | all: check 20 | 21 | .PHONY: env 22 | env: env-base env-libs 23 | 24 | .PHONY: env-base 25 | env-base: 26 | mkdir -p $(dir $(PYTHON_ENV)) 27 | tools/virtualenv --python=python$(python) $(PYTHON_ENV) 28 | rm -f distribute-*.tar.gz 29 | 30 | .PHONY: env-libs 31 | env-libs: 32 | $(PIP) install pytest 33 | 34 | .PHONY: env-clean 35 | env-clean: 36 | rm -rf $(PYTHON_ENV)/ 37 | 38 | .PHONY: env-again 39 | env-again: env-clean env 40 | 41 | .PHONY: check 42 | check: 43 | PYTHONPATH=$(SRCDIR) $(PYTHON_ENV)/bin/py.test test/ 44 | 45 | check-install: dist 46 | $(MAKE) PYTHON_ENV=build/test-$(python)-$(ARCHITECTURE) env-again 47 | build/test-$(python)-$(ARCHITECTURE)/bin/python$(python) setup.py install 48 | $(MAKE) PYTHON_ENV=build/test-$(python)-$(ARCHITECTURE) SRCDIR=test check 49 | .PHONY: check-install 50 | 51 | build/test-$(python)-$(ARCHITECTURE): 52 | mkdir -p $(dir $@) 53 | cp -R $(PYTHON_ENV) $@ 54 | 55 | dist/$(PROJECT)-$(VERSION).tar.gz: setup.py Makefile README.txt check 56 | $(PYTHON_EXE) setup.py sdist 57 | 58 | README.txt: README.md 59 | pandoc --from=markdown --to=rst $^ > $@ 60 | 61 | dist: dist/$(PROJECT)-$(VERSION).tar.gz 62 | .PHONY: dist 63 | 64 | clean: 65 | rm -rf output/ dist/ build/ MANIFEST README.txt 66 | find . -name '*.pyc' -o -name '*~' | xargs -r rm -f 67 | .PHONY: clean 68 | 69 | .PHONY: again 70 | again: clean all 71 | 72 | published: 73 | $(PYTHON_ENV)/bin/python setup.py sdist upload 74 | 75 | 76 | SCANNED_FILES=$(shell find $(SRCDIR) -type d) $(shell find test/ -type d) Makefile setup.py 77 | 78 | .PHONY: continually 79 | continually: 80 | @while true; do \ 81 | clear; \ 82 | if not make check; \ 83 | then \ 84 | notify-send --icon=error --category=build --expire-time=250 "$(PROJECT) build broken"; \ 85 | fi; \ 86 | date; \ 87 | inotifywait -r -qq -e modify -e delete $(SCANNED_FILES); \ 88 | done 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | python-parallelize 2 | ================== 3 | 4 | Simple fork/join parallelism with Python's `for` loop 5 | 6 | 7 | Quick Start 8 | ----------- 9 | 10 | Parallel iteration with a process/CPU: 11 | 12 | ```python 13 | import os 14 | from parallelize import parallelize 15 | 16 | for i in parallelize(range(100)): 17 | print(os.getpid(), i) 18 | ``` 19 | 20 | Parallel iteration with a process/item: 21 | 22 | ```python 23 | import os 24 | from parallelize import parallelize, per_item 25 | 26 | for i in parallelize(range(100), fork=per_item): 27 | print(os.getpid(), i) 28 | ``` 29 | -------------------------------------------------------------------------------- /parallelize.py: -------------------------------------------------------------------------------- 1 | 2 | from itertools import islice 3 | import os 4 | import multiprocessing 5 | 6 | 7 | def per_cpu(seq): 8 | cpu_count = multiprocessing.cpu_count() 9 | return (islice(seq, cpu, None, cpu_count) for cpu in range(cpu_count)) 10 | 11 | 12 | def per_item(seq): 13 | return ((i,) for i in seq) 14 | 15 | 16 | def parallelize(seq, fork=per_cpu): 17 | pids = [] 18 | 19 | for slice in fork(seq): 20 | pid = os.fork() 21 | if pid == 0: 22 | for item in slice: 23 | yield item 24 | os._exit(0) 25 | else: 26 | pids.append(pid) 27 | 28 | for pid in pids: 29 | os.waitpid(pid,0) 30 | 31 | 32 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | from distutils.core import setup 5 | 6 | 7 | setup(name='python-parallelize', 8 | version='1.0.0.0', 9 | description='Make the for loop run in parallel', 10 | author='Nat Pryce', 11 | author_email='about-python-parallelize@natpryce.com', 12 | url='http://github.com/npryce/python-parallelize', 13 | 14 | license="Apache 2.0", 15 | 16 | classifiers = [ 17 | 'Development Status :: 4 - Beta', 18 | 'Environment :: Console', 19 | 'Intended Audience :: Developers', 20 | 'License :: OSI Approved :: Apache Software License', 21 | 'Programming Language :: Python', 22 | 'Natural Language :: English', 23 | 'Topic :: Software Development', 24 | ], 25 | 26 | provides=['parallelize'], 27 | py_modules=['parallelize'] 28 | ) 29 | -------------------------------------------------------------------------------- /test/test_parallelize.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import multiprocessing 4 | from ctypes import c_int 5 | from parallelize import parallelize, per_item 6 | 7 | 8 | def test_runs_loop_body_in_process_per_cpu_by_default(): 9 | cpus = multiprocessing.cpu_count() 10 | pids = multiprocessing.Array(c_int, 100) 11 | sequence = range(100) 12 | 13 | for i in parallelize(sequence): 14 | pids[i] = os.getpid() 15 | 16 | assert len(set(pids)) == cpus 17 | 18 | def test_can_run_loop_body_in_process_per_item(): 19 | pids = multiprocessing.Array(c_int, 10) 20 | sequence = range(10) 21 | 22 | for i in parallelize(sequence, fork=per_item): 23 | pids[i] = os.getpid() 24 | 25 | assert len(set(pids)) == len(sequence) 26 | 27 | -------------------------------------------------------------------------------- /tools/virtualenv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Create a "virtual" Python installation 3 | """ 4 | 5 | # If you change the version here, change it in setup.py 6 | # and docs/conf.py as well. 7 | __version__ = "1.7.2" # following best practices 8 | virtualenv_version = __version__ # legacy, again 9 | 10 | import base64 11 | import sys 12 | import os 13 | import codecs 14 | import optparse 15 | import re 16 | import shutil 17 | import logging 18 | import tempfile 19 | import zlib 20 | import errno 21 | import distutils.sysconfig 22 | from distutils.util import strtobool 23 | import struct 24 | 25 | try: 26 | import subprocess 27 | except ImportError: 28 | if sys.version_info <= (2, 3): 29 | print('ERROR: %s' % sys.exc_info()[1]) 30 | print('ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.') 31 | print('If you copy subprocess.py from a newer version of Python this script will probably work') 32 | sys.exit(101) 33 | else: 34 | raise 35 | try: 36 | set 37 | except NameError: 38 | from sets import Set as set 39 | try: 40 | basestring 41 | except NameError: 42 | basestring = str 43 | 44 | try: 45 | import ConfigParser 46 | except ImportError: 47 | import configparser as ConfigParser 48 | 49 | join = os.path.join 50 | py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1]) 51 | 52 | is_jython = sys.platform.startswith('java') 53 | is_pypy = hasattr(sys, 'pypy_version_info') 54 | is_win = (sys.platform == 'win32') 55 | abiflags = getattr(sys, 'abiflags', '') 56 | 57 | user_dir = os.path.expanduser('~') 58 | if sys.platform == 'win32': 59 | user_dir = os.environ.get('APPDATA', user_dir) # Use %APPDATA% for roaming 60 | default_storage_dir = os.path.join(user_dir, 'virtualenv') 61 | else: 62 | default_storage_dir = os.path.join(user_dir, '.virtualenv') 63 | default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini') 64 | 65 | if is_pypy: 66 | expected_exe = 'pypy' 67 | elif is_jython: 68 | expected_exe = 'jython' 69 | else: 70 | expected_exe = 'python' 71 | 72 | 73 | REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath', 74 | 'fnmatch', 'locale', 'encodings', 'codecs', 75 | 'stat', 'UserDict', 'readline', 'copy_reg', 'types', 76 | 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile', 77 | 'zlib'] 78 | 79 | REQUIRED_FILES = ['lib-dynload', 'config'] 80 | 81 | majver, minver = sys.version_info[:2] 82 | if majver == 2: 83 | if minver >= 6: 84 | REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc']) 85 | if minver >= 7: 86 | REQUIRED_MODULES.extend(['_weakrefset']) 87 | if minver <= 3: 88 | REQUIRED_MODULES.extend(['sets', '__future__']) 89 | elif majver == 3: 90 | # Some extra modules are needed for Python 3, but different ones 91 | # for different versions. 92 | REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io', 93 | '_weakrefset', 'copyreg', 'tempfile', 'random', 94 | '__future__', 'collections', 'keyword', 'tarfile', 95 | 'shutil', 'struct', 'copy']) 96 | if minver >= 2: 97 | REQUIRED_FILES[-1] = 'config-%s' % majver 98 | if minver == 3: 99 | # The whole list of 3.3 modules is reproduced below - the current 100 | # uncommented ones are required for 3.3 as of now, but more may be 101 | # added as 3.3 development continues. 102 | REQUIRED_MODULES.extend([ 103 | #"aifc", 104 | #"antigravity", 105 | #"argparse", 106 | #"ast", 107 | #"asynchat", 108 | #"asyncore", 109 | "base64", 110 | #"bdb", 111 | #"binhex", 112 | "bisect", 113 | #"calendar", 114 | #"cgi", 115 | #"cgitb", 116 | #"chunk", 117 | #"cmd", 118 | #"codeop", 119 | #"code", 120 | #"colorsys", 121 | #"_compat_pickle", 122 | #"compileall", 123 | #"concurrent", 124 | #"configparser", 125 | #"contextlib", 126 | #"cProfile", 127 | #"crypt", 128 | #"csv", 129 | #"ctypes", 130 | #"curses", 131 | #"datetime", 132 | #"dbm", 133 | #"decimal", 134 | #"difflib", 135 | #"dis", 136 | #"doctest", 137 | #"dummy_threading", 138 | "_dummy_thread", 139 | #"email", 140 | #"filecmp", 141 | #"fileinput", 142 | #"formatter", 143 | #"fractions", 144 | #"ftplib", 145 | #"functools", 146 | #"getopt", 147 | #"getpass", 148 | #"gettext", 149 | #"glob", 150 | #"gzip", 151 | "hashlib", 152 | "heapq", 153 | "hmac", 154 | #"html", 155 | #"http", 156 | #"idlelib", 157 | #"imaplib", 158 | #"imghdr", 159 | #"importlib", 160 | #"inspect", 161 | #"json", 162 | #"lib2to3", 163 | #"logging", 164 | #"macpath", 165 | #"macurl2path", 166 | #"mailbox", 167 | #"mailcap", 168 | #"_markupbase", 169 | #"mimetypes", 170 | #"modulefinder", 171 | #"multiprocessing", 172 | #"netrc", 173 | #"nntplib", 174 | #"nturl2path", 175 | #"numbers", 176 | #"opcode", 177 | #"optparse", 178 | #"os2emxpath", 179 | #"pdb", 180 | #"pickle", 181 | #"pickletools", 182 | #"pipes", 183 | #"pkgutil", 184 | #"platform", 185 | #"plat-linux2", 186 | #"plistlib", 187 | #"poplib", 188 | #"pprint", 189 | #"profile", 190 | #"pstats", 191 | #"pty", 192 | #"pyclbr", 193 | #"py_compile", 194 | #"pydoc_data", 195 | #"pydoc", 196 | #"_pyio", 197 | #"queue", 198 | #"quopri", 199 | "reprlib", 200 | "rlcompleter", 201 | #"runpy", 202 | #"sched", 203 | #"shelve", 204 | #"shlex", 205 | #"smtpd", 206 | #"smtplib", 207 | #"sndhdr", 208 | #"socket", 209 | #"socketserver", 210 | #"sqlite3", 211 | #"ssl", 212 | #"stringprep", 213 | #"string", 214 | #"_strptime", 215 | #"subprocess", 216 | #"sunau", 217 | #"symbol", 218 | #"symtable", 219 | #"sysconfig", 220 | #"tabnanny", 221 | #"telnetlib", 222 | #"test", 223 | #"textwrap", 224 | #"this", 225 | #"_threading_local", 226 | #"threading", 227 | #"timeit", 228 | #"tkinter", 229 | #"tokenize", 230 | #"token", 231 | #"traceback", 232 | #"trace", 233 | #"tty", 234 | #"turtledemo", 235 | #"turtle", 236 | #"unittest", 237 | #"urllib", 238 | #"uuid", 239 | #"uu", 240 | #"wave", 241 | "weakref", 242 | #"webbrowser", 243 | #"wsgiref", 244 | #"xdrlib", 245 | #"xml", 246 | #"xmlrpc", 247 | #"zipfile", 248 | ]) 249 | 250 | if is_pypy: 251 | # these are needed to correctly display the exceptions that may happen 252 | # during the bootstrap 253 | REQUIRED_MODULES.extend(['traceback', 'linecache']) 254 | 255 | class Logger(object): 256 | 257 | """ 258 | Logging object for use in command-line script. Allows ranges of 259 | levels, to avoid some redundancy of displayed information. 260 | """ 261 | 262 | DEBUG = logging.DEBUG 263 | INFO = logging.INFO 264 | NOTIFY = (logging.INFO+logging.WARN)/2 265 | WARN = WARNING = logging.WARN 266 | ERROR = logging.ERROR 267 | FATAL = logging.FATAL 268 | 269 | LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL] 270 | 271 | def __init__(self, consumers): 272 | self.consumers = consumers 273 | self.indent = 0 274 | self.in_progress = None 275 | self.in_progress_hanging = False 276 | 277 | def debug(self, msg, *args, **kw): 278 | self.log(self.DEBUG, msg, *args, **kw) 279 | def info(self, msg, *args, **kw): 280 | self.log(self.INFO, msg, *args, **kw) 281 | def notify(self, msg, *args, **kw): 282 | self.log(self.NOTIFY, msg, *args, **kw) 283 | def warn(self, msg, *args, **kw): 284 | self.log(self.WARN, msg, *args, **kw) 285 | def error(self, msg, *args, **kw): 286 | self.log(self.WARN, msg, *args, **kw) 287 | def fatal(self, msg, *args, **kw): 288 | self.log(self.FATAL, msg, *args, **kw) 289 | def log(self, level, msg, *args, **kw): 290 | if args: 291 | if kw: 292 | raise TypeError( 293 | "You may give positional or keyword arguments, not both") 294 | args = args or kw 295 | rendered = None 296 | for consumer_level, consumer in self.consumers: 297 | if self.level_matches(level, consumer_level): 298 | if (self.in_progress_hanging 299 | and consumer in (sys.stdout, sys.stderr)): 300 | self.in_progress_hanging = False 301 | sys.stdout.write('\n') 302 | sys.stdout.flush() 303 | if rendered is None: 304 | if args: 305 | rendered = msg % args 306 | else: 307 | rendered = msg 308 | rendered = ' '*self.indent + rendered 309 | if hasattr(consumer, 'write'): 310 | consumer.write(rendered+'\n') 311 | else: 312 | consumer(rendered) 313 | 314 | def start_progress(self, msg): 315 | assert not self.in_progress, ( 316 | "Tried to start_progress(%r) while in_progress %r" 317 | % (msg, self.in_progress)) 318 | if self.level_matches(self.NOTIFY, self._stdout_level()): 319 | sys.stdout.write(msg) 320 | sys.stdout.flush() 321 | self.in_progress_hanging = True 322 | else: 323 | self.in_progress_hanging = False 324 | self.in_progress = msg 325 | 326 | def end_progress(self, msg='done.'): 327 | assert self.in_progress, ( 328 | "Tried to end_progress without start_progress") 329 | if self.stdout_level_matches(self.NOTIFY): 330 | if not self.in_progress_hanging: 331 | # Some message has been printed out since start_progress 332 | sys.stdout.write('...' + self.in_progress + msg + '\n') 333 | sys.stdout.flush() 334 | else: 335 | sys.stdout.write(msg + '\n') 336 | sys.stdout.flush() 337 | self.in_progress = None 338 | self.in_progress_hanging = False 339 | 340 | def show_progress(self): 341 | """If we are in a progress scope, and no log messages have been 342 | shown, write out another '.'""" 343 | if self.in_progress_hanging: 344 | sys.stdout.write('.') 345 | sys.stdout.flush() 346 | 347 | def stdout_level_matches(self, level): 348 | """Returns true if a message at this level will go to stdout""" 349 | return self.level_matches(level, self._stdout_level()) 350 | 351 | def _stdout_level(self): 352 | """Returns the level that stdout runs at""" 353 | for level, consumer in self.consumers: 354 | if consumer is sys.stdout: 355 | return level 356 | return self.FATAL 357 | 358 | def level_matches(self, level, consumer_level): 359 | """ 360 | >>> l = Logger([]) 361 | >>> l.level_matches(3, 4) 362 | False 363 | >>> l.level_matches(3, 2) 364 | True 365 | >>> l.level_matches(slice(None, 3), 3) 366 | False 367 | >>> l.level_matches(slice(None, 3), 2) 368 | True 369 | >>> l.level_matches(slice(1, 3), 1) 370 | True 371 | >>> l.level_matches(slice(2, 3), 1) 372 | False 373 | """ 374 | if isinstance(level, slice): 375 | start, stop = level.start, level.stop 376 | if start is not None and start > consumer_level: 377 | return False 378 | if stop is not None and stop <= consumer_level: 379 | return False 380 | return True 381 | else: 382 | return level >= consumer_level 383 | 384 | #@classmethod 385 | def level_for_integer(cls, level): 386 | levels = cls.LEVELS 387 | if level < 0: 388 | return levels[0] 389 | if level >= len(levels): 390 | return levels[-1] 391 | return levels[level] 392 | 393 | level_for_integer = classmethod(level_for_integer) 394 | 395 | # create a silent logger just to prevent this from being undefined 396 | # will be overridden with requested verbosity main() is called. 397 | logger = Logger([(Logger.LEVELS[-1], sys.stdout)]) 398 | 399 | def mkdir(path): 400 | if not os.path.exists(path): 401 | logger.info('Creating %s', path) 402 | os.makedirs(path) 403 | else: 404 | logger.info('Directory %s already exists', path) 405 | 406 | def copyfileordir(src, dest): 407 | if os.path.isdir(src): 408 | shutil.copytree(src, dest, True) 409 | else: 410 | shutil.copy2(src, dest) 411 | 412 | def copyfile(src, dest, symlink=True): 413 | if not os.path.exists(src): 414 | # Some bad symlink in the src 415 | logger.warn('Cannot find file %s (bad symlink)', src) 416 | return 417 | if os.path.exists(dest): 418 | logger.debug('File %s already exists', dest) 419 | return 420 | if not os.path.exists(os.path.dirname(dest)): 421 | logger.info('Creating parent directories for %s' % os.path.dirname(dest)) 422 | os.makedirs(os.path.dirname(dest)) 423 | if not os.path.islink(src): 424 | srcpath = os.path.abspath(src) 425 | else: 426 | srcpath = os.readlink(src) 427 | if symlink and hasattr(os, 'symlink') and not is_win: 428 | logger.info('Symlinking %s', dest) 429 | try: 430 | os.symlink(srcpath, dest) 431 | except (OSError, NotImplementedError): 432 | logger.info('Symlinking failed, copying to %s', dest) 433 | copyfileordir(src, dest) 434 | else: 435 | logger.info('Copying to %s', dest) 436 | copyfileordir(src, dest) 437 | 438 | def writefile(dest, content, overwrite=True): 439 | if not os.path.exists(dest): 440 | logger.info('Writing %s', dest) 441 | f = open(dest, 'wb') 442 | f.write(content.encode('utf-8')) 443 | f.close() 444 | return 445 | else: 446 | f = open(dest, 'rb') 447 | c = f.read() 448 | f.close() 449 | if c != content.encode("utf-8"): 450 | if not overwrite: 451 | logger.notify('File %s exists with different content; not overwriting', dest) 452 | return 453 | logger.notify('Overwriting %s with new content', dest) 454 | f = open(dest, 'wb') 455 | f.write(content.encode('utf-8')) 456 | f.close() 457 | else: 458 | logger.info('Content %s already in place', dest) 459 | 460 | def rmtree(dir): 461 | if os.path.exists(dir): 462 | logger.notify('Deleting tree %s', dir) 463 | shutil.rmtree(dir) 464 | else: 465 | logger.info('Do not need to delete %s; already gone', dir) 466 | 467 | def make_exe(fn): 468 | if hasattr(os, 'chmod'): 469 | oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777 470 | newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777 471 | os.chmod(fn, newmode) 472 | logger.info('Changed mode of %s to %s', fn, oct(newmode)) 473 | 474 | def _find_file(filename, dirs): 475 | for dir in reversed(dirs): 476 | if os.path.exists(join(dir, filename)): 477 | return join(dir, filename) 478 | return filename 479 | 480 | def _install_req(py_executable, unzip=False, distribute=False, 481 | search_dirs=None, never_download=False): 482 | 483 | if search_dirs is None: 484 | search_dirs = file_search_dirs() 485 | 486 | if not distribute: 487 | setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3] 488 | project_name = 'setuptools' 489 | bootstrap_script = EZ_SETUP_PY 490 | source = None 491 | else: 492 | setup_fn = None 493 | source = 'distribute-0.6.27.tar.gz' 494 | project_name = 'distribute' 495 | bootstrap_script = DISTRIBUTE_SETUP_PY 496 | 497 | if setup_fn is not None: 498 | setup_fn = _find_file(setup_fn, search_dirs) 499 | 500 | if source is not None: 501 | source = _find_file(source, search_dirs) 502 | 503 | if is_jython and os._name == 'nt': 504 | # Jython's .bat sys.executable can't handle a command line 505 | # argument with newlines 506 | fd, ez_setup = tempfile.mkstemp('.py') 507 | os.write(fd, bootstrap_script) 508 | os.close(fd) 509 | cmd = [py_executable, ez_setup] 510 | else: 511 | cmd = [py_executable, '-c', bootstrap_script] 512 | if unzip: 513 | cmd.append('--always-unzip') 514 | env = {} 515 | remove_from_env = [] 516 | if logger.stdout_level_matches(logger.DEBUG): 517 | cmd.append('-v') 518 | 519 | old_chdir = os.getcwd() 520 | if setup_fn is not None and os.path.exists(setup_fn): 521 | logger.info('Using existing %s egg: %s' % (project_name, setup_fn)) 522 | cmd.append(setup_fn) 523 | if os.environ.get('PYTHONPATH'): 524 | env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH'] 525 | else: 526 | env['PYTHONPATH'] = setup_fn 527 | else: 528 | # the source is found, let's chdir 529 | if source is not None and os.path.exists(source): 530 | logger.info('Using existing %s egg: %s' % (project_name, source)) 531 | os.chdir(os.path.dirname(source)) 532 | # in this case, we want to be sure that PYTHONPATH is unset (not 533 | # just empty, really unset), else CPython tries to import the 534 | # site.py that it's in virtualenv_support 535 | remove_from_env.append('PYTHONPATH') 536 | else: 537 | if never_download: 538 | logger.fatal("Can't find any local distributions of %s to install " 539 | "and --never-download is set. Either re-run virtualenv " 540 | "without the --never-download option, or place a %s " 541 | "distribution (%s) in one of these " 542 | "locations: %r" % (project_name, project_name, 543 | setup_fn or source, 544 | search_dirs)) 545 | sys.exit(1) 546 | 547 | logger.info('No %s egg found; downloading' % project_name) 548 | cmd.extend(['--always-copy', '-U', project_name]) 549 | logger.start_progress('Installing %s...' % project_name) 550 | logger.indent += 2 551 | cwd = None 552 | if project_name == 'distribute': 553 | env['DONT_PATCH_SETUPTOOLS'] = 'true' 554 | 555 | def _filter_ez_setup(line): 556 | return filter_ez_setup(line, project_name) 557 | 558 | if not os.access(os.getcwd(), os.W_OK): 559 | cwd = tempfile.mkdtemp() 560 | if source is not None and os.path.exists(source): 561 | # the current working dir is hostile, let's copy the 562 | # tarball to a temp dir 563 | target = os.path.join(cwd, os.path.split(source)[-1]) 564 | shutil.copy(source, target) 565 | try: 566 | call_subprocess(cmd, show_stdout=False, 567 | filter_stdout=_filter_ez_setup, 568 | extra_env=env, 569 | remove_from_env=remove_from_env, 570 | cwd=cwd) 571 | finally: 572 | logger.indent -= 2 573 | logger.end_progress() 574 | if cwd is not None: 575 | shutil.rmtree(cwd) 576 | if os.getcwd() != old_chdir: 577 | os.chdir(old_chdir) 578 | if is_jython and os._name == 'nt': 579 | os.remove(ez_setup) 580 | 581 | def file_search_dirs(): 582 | here = os.path.dirname(os.path.abspath(__file__)) 583 | dirs = ['.', here, 584 | join(here, 'virtualenv_support')] 585 | if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv': 586 | # Probably some boot script; just in case virtualenv is installed... 587 | try: 588 | import virtualenv 589 | except ImportError: 590 | pass 591 | else: 592 | dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support')) 593 | return [d for d in dirs if os.path.isdir(d)] 594 | 595 | def install_setuptools(py_executable, unzip=False, 596 | search_dirs=None, never_download=False): 597 | _install_req(py_executable, unzip, 598 | search_dirs=search_dirs, never_download=never_download) 599 | 600 | def install_distribute(py_executable, unzip=False, 601 | search_dirs=None, never_download=False): 602 | _install_req(py_executable, unzip, distribute=True, 603 | search_dirs=search_dirs, never_download=never_download) 604 | 605 | _pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I) 606 | def install_pip(py_executable, search_dirs=None, never_download=False): 607 | if search_dirs is None: 608 | search_dirs = file_search_dirs() 609 | 610 | filenames = [] 611 | for dir in search_dirs: 612 | filenames.extend([join(dir, fn) for fn in os.listdir(dir) 613 | if _pip_re.search(fn)]) 614 | filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)] 615 | filenames.sort() 616 | filenames = [filename for basename, i, filename in filenames] 617 | if not filenames: 618 | filename = 'pip' 619 | else: 620 | filename = filenames[-1] 621 | easy_install_script = 'easy_install' 622 | if sys.platform == 'win32': 623 | easy_install_script = 'easy_install-script.py' 624 | # There's two subtle issues here when invoking easy_install. 625 | # 1. On unix-like systems the easy_install script can *only* be executed 626 | # directly if its full filesystem path is no longer than 78 characters. 627 | # 2. A work around to [1] is to use the `python path/to/easy_install foo` 628 | # pattern, but that breaks if the path contains non-ASCII characters, as 629 | # you can't put the file encoding declaration before the shebang line. 630 | # The solution is to use Python's -x flag to skip the first line of the 631 | # script (and any ASCII decoding errors that may have occurred in that line) 632 | cmd = [py_executable, '-x', join(os.path.dirname(py_executable), easy_install_script), filename] 633 | # jython and pypy don't yet support -x 634 | if is_jython or is_pypy: 635 | cmd.remove('-x') 636 | if filename == 'pip': 637 | if never_download: 638 | logger.fatal("Can't find any local distributions of pip to install " 639 | "and --never-download is set. Either re-run virtualenv " 640 | "without the --never-download option, or place a pip " 641 | "source distribution (zip/tar.gz/tar.bz2) in one of these " 642 | "locations: %r" % search_dirs) 643 | sys.exit(1) 644 | logger.info('Installing pip from network...') 645 | else: 646 | logger.info('Installing existing %s distribution: %s' % ( 647 | os.path.basename(filename), filename)) 648 | logger.start_progress('Installing pip...') 649 | logger.indent += 2 650 | def _filter_setup(line): 651 | return filter_ez_setup(line, 'pip') 652 | try: 653 | call_subprocess(cmd, show_stdout=False, 654 | filter_stdout=_filter_setup) 655 | finally: 656 | logger.indent -= 2 657 | logger.end_progress() 658 | 659 | def filter_ez_setup(line, project_name='setuptools'): 660 | if not line.strip(): 661 | return Logger.DEBUG 662 | if project_name == 'distribute': 663 | for prefix in ('Extracting', 'Now working', 'Installing', 'Before', 664 | 'Scanning', 'Setuptools', 'Egg', 'Already', 665 | 'running', 'writing', 'reading', 'installing', 666 | 'creating', 'copying', 'byte-compiling', 'removing', 667 | 'Processing'): 668 | if line.startswith(prefix): 669 | return Logger.DEBUG 670 | return Logger.DEBUG 671 | for prefix in ['Reading ', 'Best match', 'Processing setuptools', 672 | 'Copying setuptools', 'Adding setuptools', 673 | 'Installing ', 'Installed ']: 674 | if line.startswith(prefix): 675 | return Logger.DEBUG 676 | return Logger.INFO 677 | 678 | 679 | class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter): 680 | """ 681 | Custom help formatter for use in ConfigOptionParser that updates 682 | the defaults before expanding them, allowing them to show up correctly 683 | in the help listing 684 | """ 685 | def expand_default(self, option): 686 | if self.parser is not None: 687 | self.parser.update_defaults(self.parser.defaults) 688 | return optparse.IndentedHelpFormatter.expand_default(self, option) 689 | 690 | 691 | class ConfigOptionParser(optparse.OptionParser): 692 | """ 693 | Custom option parser which updates its defaults by by checking the 694 | configuration files and environmental variables 695 | """ 696 | def __init__(self, *args, **kwargs): 697 | self.config = ConfigParser.RawConfigParser() 698 | self.files = self.get_config_files() 699 | self.config.read(self.files) 700 | optparse.OptionParser.__init__(self, *args, **kwargs) 701 | 702 | def get_config_files(self): 703 | config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False) 704 | if config_file and os.path.exists(config_file): 705 | return [config_file] 706 | return [default_config_file] 707 | 708 | def update_defaults(self, defaults): 709 | """ 710 | Updates the given defaults with values from the config files and 711 | the environ. Does a little special handling for certain types of 712 | options (lists). 713 | """ 714 | # Then go and look for the other sources of configuration: 715 | config = {} 716 | # 1. config files 717 | config.update(dict(self.get_config_section('virtualenv'))) 718 | # 2. environmental variables 719 | config.update(dict(self.get_environ_vars())) 720 | # Then set the options with those values 721 | for key, val in config.items(): 722 | key = key.replace('_', '-') 723 | if not key.startswith('--'): 724 | key = '--%s' % key # only prefer long opts 725 | option = self.get_option(key) 726 | if option is not None: 727 | # ignore empty values 728 | if not val: 729 | continue 730 | # handle multiline configs 731 | if option.action == 'append': 732 | val = val.split() 733 | else: 734 | option.nargs = 1 735 | if option.action in ('store_true', 'store_false', 'count'): 736 | val = strtobool(val) 737 | try: 738 | val = option.convert_value(key, val) 739 | except optparse.OptionValueError: 740 | e = sys.exc_info()[1] 741 | print("An error occured during configuration: %s" % e) 742 | sys.exit(3) 743 | defaults[option.dest] = val 744 | return defaults 745 | 746 | def get_config_section(self, name): 747 | """ 748 | Get a section of a configuration 749 | """ 750 | if self.config.has_section(name): 751 | return self.config.items(name) 752 | return [] 753 | 754 | def get_environ_vars(self, prefix='VIRTUALENV_'): 755 | """ 756 | Returns a generator with all environmental vars with prefix VIRTUALENV 757 | """ 758 | for key, val in os.environ.items(): 759 | if key.startswith(prefix): 760 | yield (key.replace(prefix, '').lower(), val) 761 | 762 | def get_default_values(self): 763 | """ 764 | Overridding to make updating the defaults after instantiation of 765 | the option parser possible, update_defaults() does the dirty work. 766 | """ 767 | if not self.process_default_values: 768 | # Old, pre-Optik 1.5 behaviour. 769 | return optparse.Values(self.defaults) 770 | 771 | defaults = self.update_defaults(self.defaults.copy()) # ours 772 | for option in self._get_all_options(): 773 | default = defaults.get(option.dest) 774 | if isinstance(default, basestring): 775 | opt_str = option.get_opt_string() 776 | defaults[option.dest] = option.check_value(opt_str, default) 777 | return optparse.Values(defaults) 778 | 779 | 780 | def main(): 781 | parser = ConfigOptionParser( 782 | version=virtualenv_version, 783 | usage="%prog [OPTIONS] DEST_DIR", 784 | formatter=UpdatingDefaultsHelpFormatter()) 785 | 786 | parser.add_option( 787 | '-v', '--verbose', 788 | action='count', 789 | dest='verbose', 790 | default=0, 791 | help="Increase verbosity") 792 | 793 | parser.add_option( 794 | '-q', '--quiet', 795 | action='count', 796 | dest='quiet', 797 | default=0, 798 | help='Decrease verbosity') 799 | 800 | parser.add_option( 801 | '-p', '--python', 802 | dest='python', 803 | metavar='PYTHON_EXE', 804 | help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 ' 805 | 'interpreter to create the new environment. The default is the interpreter that ' 806 | 'virtualenv was installed with (%s)' % sys.executable) 807 | 808 | parser.add_option( 809 | '--clear', 810 | dest='clear', 811 | action='store_true', 812 | help="Clear out the non-root install and start from scratch") 813 | 814 | parser.add_option( 815 | '--no-site-packages', 816 | dest='no_site_packages', 817 | action='store_true', 818 | help="Don't give access to the global site-packages dir to the " 819 | "virtual environment (default; deprecated)") 820 | 821 | parser.add_option( 822 | '--system-site-packages', 823 | dest='system_site_packages', 824 | action='store_true', 825 | help="Give access to the global site-packages dir to the " 826 | "virtual environment") 827 | 828 | parser.add_option( 829 | '--unzip-setuptools', 830 | dest='unzip_setuptools', 831 | action='store_true', 832 | help="Unzip Setuptools or Distribute when installing it") 833 | 834 | parser.add_option( 835 | '--relocatable', 836 | dest='relocatable', 837 | action='store_true', 838 | help='Make an EXISTING virtualenv environment relocatable. ' 839 | 'This fixes up scripts and makes all .pth files relative') 840 | 841 | parser.add_option( 842 | '--distribute', '--use-distribute', # the second option is for legacy reasons here. Hi Kenneth! 843 | dest='use_distribute', 844 | action='store_true', 845 | help='Use Distribute instead of Setuptools. Set environ variable ' 846 | 'VIRTUALENV_DISTRIBUTE to make it the default ') 847 | 848 | default_search_dirs = file_search_dirs() 849 | parser.add_option( 850 | '--extra-search-dir', 851 | dest="search_dirs", 852 | action="append", 853 | default=default_search_dirs, 854 | help="Directory to look for setuptools/distribute/pip distributions in. " 855 | "You can add any number of additional --extra-search-dir paths.") 856 | 857 | parser.add_option( 858 | '--never-download', 859 | dest="never_download", 860 | action="store_true", 861 | help="Never download anything from the network. Instead, virtualenv will fail " 862 | "if local distributions of setuptools/distribute/pip are not present.") 863 | 864 | parser.add_option( 865 | '--prompt', 866 | dest='prompt', 867 | help='Provides an alternative prompt prefix for this environment') 868 | 869 | if 'extend_parser' in globals(): 870 | extend_parser(parser) 871 | 872 | options, args = parser.parse_args() 873 | 874 | global logger 875 | 876 | if 'adjust_options' in globals(): 877 | adjust_options(options, args) 878 | 879 | verbosity = options.verbose - options.quiet 880 | logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)]) 881 | 882 | if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): 883 | env = os.environ.copy() 884 | interpreter = resolve_interpreter(options.python) 885 | if interpreter == sys.executable: 886 | logger.warn('Already using interpreter %s' % interpreter) 887 | else: 888 | logger.notify('Running virtualenv with interpreter %s' % interpreter) 889 | env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true' 890 | file = __file__ 891 | if file.endswith('.pyc'): 892 | file = file[:-1] 893 | popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env) 894 | raise SystemExit(popen.wait()) 895 | 896 | # Force --distribute on Python 3, since setuptools is not available. 897 | if majver > 2: 898 | options.use_distribute = True 899 | 900 | if os.environ.get('PYTHONDONTWRITEBYTECODE') and not options.use_distribute: 901 | print( 902 | "The PYTHONDONTWRITEBYTECODE environment variable is " 903 | "not compatible with setuptools. Either use --distribute " 904 | "or unset PYTHONDONTWRITEBYTECODE.") 905 | sys.exit(2) 906 | if not args: 907 | print('You must provide a DEST_DIR') 908 | parser.print_help() 909 | sys.exit(2) 910 | if len(args) > 1: 911 | print('There must be only one argument: DEST_DIR (you gave %s)' % ( 912 | ' '.join(args))) 913 | parser.print_help() 914 | sys.exit(2) 915 | 916 | home_dir = args[0] 917 | 918 | if os.environ.get('WORKING_ENV'): 919 | logger.fatal('ERROR: you cannot run virtualenv while in a workingenv') 920 | logger.fatal('Please deactivate your workingenv, then re-run this script') 921 | sys.exit(3) 922 | 923 | if 'PYTHONHOME' in os.environ: 924 | logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it') 925 | del os.environ['PYTHONHOME'] 926 | 927 | if options.relocatable: 928 | make_environment_relocatable(home_dir) 929 | return 930 | 931 | if options.no_site_packages: 932 | logger.warn('The --no-site-packages flag is deprecated; it is now ' 933 | 'the default behavior.') 934 | 935 | create_environment(home_dir, 936 | site_packages=options.system_site_packages, 937 | clear=options.clear, 938 | unzip_setuptools=options.unzip_setuptools, 939 | use_distribute=options.use_distribute, 940 | prompt=options.prompt, 941 | search_dirs=options.search_dirs, 942 | never_download=options.never_download) 943 | if 'after_install' in globals(): 944 | after_install(options, home_dir) 945 | 946 | def call_subprocess(cmd, show_stdout=True, 947 | filter_stdout=None, cwd=None, 948 | raise_on_returncode=True, extra_env=None, 949 | remove_from_env=None): 950 | cmd_parts = [] 951 | for part in cmd: 952 | if len(part) > 45: 953 | part = part[:20]+"..."+part[-20:] 954 | if ' ' in part or '\n' in part or '"' in part or "'" in part: 955 | part = '"%s"' % part.replace('"', '\\"') 956 | if hasattr(part, 'decode'): 957 | try: 958 | part = part.decode(sys.getdefaultencoding()) 959 | except UnicodeDecodeError: 960 | part = part.decode(sys.getfilesystemencoding()) 961 | cmd_parts.append(part) 962 | cmd_desc = ' '.join(cmd_parts) 963 | if show_stdout: 964 | stdout = None 965 | else: 966 | stdout = subprocess.PIPE 967 | logger.debug("Running command %s" % cmd_desc) 968 | if extra_env or remove_from_env: 969 | env = os.environ.copy() 970 | if extra_env: 971 | env.update(extra_env) 972 | if remove_from_env: 973 | for varname in remove_from_env: 974 | env.pop(varname, None) 975 | else: 976 | env = None 977 | try: 978 | proc = subprocess.Popen( 979 | cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout, 980 | cwd=cwd, env=env) 981 | except Exception: 982 | e = sys.exc_info()[1] 983 | logger.fatal( 984 | "Error %s while executing command %s" % (e, cmd_desc)) 985 | raise 986 | all_output = [] 987 | if stdout is not None: 988 | stdout = proc.stdout 989 | encoding = sys.getdefaultencoding() 990 | fs_encoding = sys.getfilesystemencoding() 991 | while 1: 992 | line = stdout.readline() 993 | try: 994 | line = line.decode(encoding) 995 | except UnicodeDecodeError: 996 | line = line.decode(fs_encoding) 997 | if not line: 998 | break 999 | line = line.rstrip() 1000 | all_output.append(line) 1001 | if filter_stdout: 1002 | level = filter_stdout(line) 1003 | if isinstance(level, tuple): 1004 | level, line = level 1005 | logger.log(level, line) 1006 | if not logger.stdout_level_matches(level): 1007 | logger.show_progress() 1008 | else: 1009 | logger.info(line) 1010 | else: 1011 | proc.communicate() 1012 | proc.wait() 1013 | if proc.returncode: 1014 | if raise_on_returncode: 1015 | if all_output: 1016 | logger.notify('Complete output from command %s:' % cmd_desc) 1017 | logger.notify('\n'.join(all_output) + '\n----------------------------------------') 1018 | raise OSError( 1019 | "Command %s failed with error code %s" 1020 | % (cmd_desc, proc.returncode)) 1021 | else: 1022 | logger.warn( 1023 | "Command %s had error code %s" 1024 | % (cmd_desc, proc.returncode)) 1025 | 1026 | 1027 | def create_environment(home_dir, site_packages=False, clear=False, 1028 | unzip_setuptools=False, use_distribute=False, 1029 | prompt=None, search_dirs=None, never_download=False): 1030 | """ 1031 | Creates a new environment in ``home_dir``. 1032 | 1033 | If ``site_packages`` is true, then the global ``site-packages/`` 1034 | directory will be on the path. 1035 | 1036 | If ``clear`` is true (default False) then the environment will 1037 | first be cleared. 1038 | """ 1039 | home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1040 | 1041 | py_executable = os.path.abspath(install_python( 1042 | home_dir, lib_dir, inc_dir, bin_dir, 1043 | site_packages=site_packages, clear=clear)) 1044 | 1045 | install_distutils(home_dir) 1046 | 1047 | if use_distribute: 1048 | install_distribute(py_executable, unzip=unzip_setuptools, 1049 | search_dirs=search_dirs, never_download=never_download) 1050 | else: 1051 | install_setuptools(py_executable, unzip=unzip_setuptools, 1052 | search_dirs=search_dirs, never_download=never_download) 1053 | 1054 | install_pip(py_executable, search_dirs=search_dirs, never_download=never_download) 1055 | 1056 | install_activate(home_dir, bin_dir, prompt) 1057 | 1058 | def path_locations(home_dir): 1059 | """Return the path locations for the environment (where libraries are, 1060 | where scripts go, etc)""" 1061 | # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its 1062 | # prefix arg is broken: http://bugs.python.org/issue3386 1063 | if sys.platform == 'win32': 1064 | # Windows has lots of problems with executables with spaces in 1065 | # the name; this function will remove them (using the ~1 1066 | # format): 1067 | mkdir(home_dir) 1068 | if ' ' in home_dir: 1069 | try: 1070 | import win32api 1071 | except ImportError: 1072 | print('Error: the path "%s" has a space in it' % home_dir) 1073 | print('To handle these kinds of paths, the win32api module must be installed:') 1074 | print(' http://sourceforge.net/projects/pywin32/') 1075 | sys.exit(3) 1076 | home_dir = win32api.GetShortPathName(home_dir) 1077 | lib_dir = join(home_dir, 'Lib') 1078 | inc_dir = join(home_dir, 'Include') 1079 | bin_dir = join(home_dir, 'Scripts') 1080 | if is_jython: 1081 | lib_dir = join(home_dir, 'Lib') 1082 | inc_dir = join(home_dir, 'Include') 1083 | bin_dir = join(home_dir, 'bin') 1084 | elif is_pypy: 1085 | lib_dir = home_dir 1086 | inc_dir = join(home_dir, 'include') 1087 | bin_dir = join(home_dir, 'bin') 1088 | elif sys.platform != 'win32': 1089 | lib_dir = join(home_dir, 'lib', py_version) 1090 | inc_dir = join(home_dir, 'include', py_version + abiflags) 1091 | bin_dir = join(home_dir, 'bin') 1092 | return home_dir, lib_dir, inc_dir, bin_dir 1093 | 1094 | 1095 | def change_prefix(filename, dst_prefix): 1096 | prefixes = [sys.prefix] 1097 | 1098 | if sys.platform == "darwin": 1099 | prefixes.extend(( 1100 | os.path.join("/Library/Python", sys.version[:3], "site-packages"), 1101 | os.path.join(sys.prefix, "Extras", "lib", "python"), 1102 | os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"))) 1103 | 1104 | if hasattr(sys, 'real_prefix'): 1105 | prefixes.append(sys.real_prefix) 1106 | prefixes = list(map(os.path.abspath, prefixes)) 1107 | filename = os.path.abspath(filename) 1108 | for src_prefix in prefixes: 1109 | if filename.startswith(src_prefix): 1110 | _, relpath = filename.split(src_prefix, 1) 1111 | assert relpath[0] == os.sep 1112 | relpath = relpath[1:] 1113 | return join(dst_prefix, relpath) 1114 | assert False, "Filename %s does not start with any of these prefixes: %s" % \ 1115 | (filename, prefixes) 1116 | 1117 | def copy_required_modules(dst_prefix): 1118 | import imp 1119 | # If we are running under -p, we need to remove the current 1120 | # directory from sys.path temporarily here, so that we 1121 | # definitely get the modules from the site directory of 1122 | # the interpreter we are running under, not the one 1123 | # virtualenv.py is installed under (which might lead to py2/py3 1124 | # incompatibility issues) 1125 | _prev_sys_path = sys.path 1126 | if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): 1127 | sys.path = sys.path[1:] 1128 | try: 1129 | for modname in REQUIRED_MODULES: 1130 | if modname in sys.builtin_module_names: 1131 | logger.info("Ignoring built-in bootstrap module: %s" % modname) 1132 | continue 1133 | try: 1134 | f, filename, _ = imp.find_module(modname) 1135 | except ImportError: 1136 | logger.info("Cannot import bootstrap module: %s" % modname) 1137 | else: 1138 | if f is not None: 1139 | f.close() 1140 | dst_filename = change_prefix(filename, dst_prefix) 1141 | copyfile(filename, dst_filename) 1142 | if filename.endswith('.pyc'): 1143 | pyfile = filename[:-1] 1144 | if os.path.exists(pyfile): 1145 | copyfile(pyfile, dst_filename[:-1]) 1146 | finally: 1147 | sys.path = _prev_sys_path 1148 | 1149 | def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear): 1150 | """Install just the base environment, no distutils patches etc""" 1151 | if sys.executable.startswith(bin_dir): 1152 | print('Please use the *system* python to run this script') 1153 | return 1154 | 1155 | if clear: 1156 | rmtree(lib_dir) 1157 | ## FIXME: why not delete it? 1158 | ## Maybe it should delete everything with #!/path/to/venv/python in it 1159 | logger.notify('Not deleting %s', bin_dir) 1160 | 1161 | if hasattr(sys, 'real_prefix'): 1162 | logger.notify('Using real prefix %r' % sys.real_prefix) 1163 | prefix = sys.real_prefix 1164 | else: 1165 | prefix = sys.prefix 1166 | mkdir(lib_dir) 1167 | fix_lib64(lib_dir) 1168 | stdlib_dirs = [os.path.dirname(os.__file__)] 1169 | if sys.platform == 'win32': 1170 | stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs')) 1171 | elif sys.platform == 'darwin': 1172 | stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages')) 1173 | if hasattr(os, 'symlink'): 1174 | logger.info('Symlinking Python bootstrap modules') 1175 | else: 1176 | logger.info('Copying Python bootstrap modules') 1177 | logger.indent += 2 1178 | try: 1179 | # copy required files... 1180 | for stdlib_dir in stdlib_dirs: 1181 | if not os.path.isdir(stdlib_dir): 1182 | continue 1183 | for fn in os.listdir(stdlib_dir): 1184 | bn = os.path.splitext(fn)[0] 1185 | if fn != 'site-packages' and bn in REQUIRED_FILES: 1186 | copyfile(join(stdlib_dir, fn), join(lib_dir, fn)) 1187 | # ...and modules 1188 | copy_required_modules(home_dir) 1189 | finally: 1190 | logger.indent -= 2 1191 | mkdir(join(lib_dir, 'site-packages')) 1192 | import site 1193 | site_filename = site.__file__ 1194 | if site_filename.endswith('.pyc'): 1195 | site_filename = site_filename[:-1] 1196 | elif site_filename.endswith('$py.class'): 1197 | site_filename = site_filename.replace('$py.class', '.py') 1198 | site_filename_dst = change_prefix(site_filename, home_dir) 1199 | site_dir = os.path.dirname(site_filename_dst) 1200 | writefile(site_filename_dst, SITE_PY) 1201 | writefile(join(site_dir, 'orig-prefix.txt'), prefix) 1202 | site_packages_filename = join(site_dir, 'no-global-site-packages.txt') 1203 | if not site_packages: 1204 | writefile(site_packages_filename, '') 1205 | else: 1206 | if os.path.exists(site_packages_filename): 1207 | logger.info('Deleting %s' % site_packages_filename) 1208 | os.unlink(site_packages_filename) 1209 | 1210 | if is_pypy or is_win: 1211 | stdinc_dir = join(prefix, 'include') 1212 | else: 1213 | stdinc_dir = join(prefix, 'include', py_version + abiflags) 1214 | if os.path.exists(stdinc_dir): 1215 | copyfile(stdinc_dir, inc_dir) 1216 | else: 1217 | logger.debug('No include dir %s' % stdinc_dir) 1218 | 1219 | # pypy never uses exec_prefix, just ignore it 1220 | if sys.exec_prefix != prefix and not is_pypy: 1221 | if sys.platform == 'win32': 1222 | exec_dir = join(sys.exec_prefix, 'lib') 1223 | elif is_jython: 1224 | exec_dir = join(sys.exec_prefix, 'Lib') 1225 | else: 1226 | exec_dir = join(sys.exec_prefix, 'lib', py_version) 1227 | for fn in os.listdir(exec_dir): 1228 | copyfile(join(exec_dir, fn), join(lib_dir, fn)) 1229 | 1230 | if is_jython: 1231 | # Jython has either jython-dev.jar and javalib/ dir, or just 1232 | # jython.jar 1233 | for name in 'jython-dev.jar', 'javalib', 'jython.jar': 1234 | src = join(prefix, name) 1235 | if os.path.exists(src): 1236 | copyfile(src, join(home_dir, name)) 1237 | # XXX: registry should always exist after Jython 2.5rc1 1238 | src = join(prefix, 'registry') 1239 | if os.path.exists(src): 1240 | copyfile(src, join(home_dir, 'registry'), symlink=False) 1241 | copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'), 1242 | symlink=False) 1243 | 1244 | mkdir(bin_dir) 1245 | py_executable = join(bin_dir, os.path.basename(sys.executable)) 1246 | if 'Python.framework' in prefix: 1247 | if re.search(r'/Python(?:-32|-64)*$', py_executable): 1248 | # The name of the python executable is not quite what 1249 | # we want, rename it. 1250 | py_executable = os.path.join( 1251 | os.path.dirname(py_executable), 'python') 1252 | 1253 | logger.notify('New %s executable in %s', expected_exe, py_executable) 1254 | pcbuild_dir = os.path.dirname(sys.executable) 1255 | pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth') 1256 | if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')): 1257 | logger.notify('Detected python running from build directory %s', pcbuild_dir) 1258 | logger.notify('Writing .pth file linking to build directory for *.pyd files') 1259 | writefile(pyd_pth, pcbuild_dir) 1260 | else: 1261 | pcbuild_dir = None 1262 | if os.path.exists(pyd_pth): 1263 | logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth) 1264 | os.unlink(pyd_pth) 1265 | 1266 | if sys.executable != py_executable: 1267 | ## FIXME: could I just hard link? 1268 | executable = sys.executable 1269 | if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'): 1270 | # Cygwin misreports sys.executable sometimes 1271 | executable += '.exe' 1272 | py_executable += '.exe' 1273 | logger.info('Executable actually exists in %s' % executable) 1274 | shutil.copyfile(executable, py_executable) 1275 | make_exe(py_executable) 1276 | if sys.platform == 'win32' or sys.platform == 'cygwin': 1277 | pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe') 1278 | if os.path.exists(pythonw): 1279 | logger.info('Also created pythonw.exe') 1280 | shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe')) 1281 | python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe') 1282 | python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe') 1283 | if os.path.exists(python_d): 1284 | logger.info('Also created python_d.exe') 1285 | shutil.copyfile(python_d, python_d_dest) 1286 | elif os.path.exists(python_d_dest): 1287 | logger.info('Removed python_d.exe as it is no longer at the source') 1288 | os.unlink(python_d_dest) 1289 | # we need to copy the DLL to enforce that windows will load the correct one. 1290 | # may not exist if we are cygwin. 1291 | py_executable_dll = 'python%s%s.dll' % ( 1292 | sys.version_info[0], sys.version_info[1]) 1293 | py_executable_dll_d = 'python%s%s_d.dll' % ( 1294 | sys.version_info[0], sys.version_info[1]) 1295 | pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll) 1296 | pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d) 1297 | pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d) 1298 | if os.path.exists(pythondll): 1299 | logger.info('Also created %s' % py_executable_dll) 1300 | shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll)) 1301 | if os.path.exists(pythondll_d): 1302 | logger.info('Also created %s' % py_executable_dll_d) 1303 | shutil.copyfile(pythondll_d, pythondll_d_dest) 1304 | elif os.path.exists(pythondll_d_dest): 1305 | logger.info('Removed %s as the source does not exist' % pythondll_d_dest) 1306 | os.unlink(pythondll_d_dest) 1307 | if is_pypy: 1308 | # make a symlink python --> pypy-c 1309 | python_executable = os.path.join(os.path.dirname(py_executable), 'python') 1310 | if sys.platform in ('win32', 'cygwin'): 1311 | python_executable += '.exe' 1312 | logger.info('Also created executable %s' % python_executable) 1313 | copyfile(py_executable, python_executable) 1314 | 1315 | if sys.platform == 'win32': 1316 | for name in 'libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', 'libeay32.dll', 'ssleay32.dll', 'sqlite.dll': 1317 | src = join(prefix, name) 1318 | if os.path.exists(src): 1319 | copyfile(src, join(bin_dir, name)) 1320 | 1321 | if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe: 1322 | secondary_exe = os.path.join(os.path.dirname(py_executable), 1323 | expected_exe) 1324 | py_executable_ext = os.path.splitext(py_executable)[1] 1325 | if py_executable_ext == '.exe': 1326 | # python2.4 gives an extension of '.4' :P 1327 | secondary_exe += py_executable_ext 1328 | if os.path.exists(secondary_exe): 1329 | logger.warn('Not overwriting existing %s script %s (you must use %s)' 1330 | % (expected_exe, secondary_exe, py_executable)) 1331 | else: 1332 | logger.notify('Also creating executable in %s' % secondary_exe) 1333 | shutil.copyfile(sys.executable, secondary_exe) 1334 | make_exe(secondary_exe) 1335 | 1336 | if '.framework' in prefix: 1337 | if 'Python.framework' in prefix: 1338 | logger.debug('MacOSX Python framework detected') 1339 | # Make sure we use the the embedded interpreter inside 1340 | # the framework, even if sys.executable points to 1341 | # the stub executable in ${sys.prefix}/bin 1342 | # See http://groups.google.com/group/python-virtualenv/ 1343 | # browse_thread/thread/17cab2f85da75951 1344 | original_python = os.path.join( 1345 | prefix, 'Resources/Python.app/Contents/MacOS/Python') 1346 | if 'EPD' in prefix: 1347 | logger.debug('EPD framework detected') 1348 | original_python = os.path.join(prefix, 'bin/python') 1349 | shutil.copy(original_python, py_executable) 1350 | 1351 | # Copy the framework's dylib into the virtual 1352 | # environment 1353 | virtual_lib = os.path.join(home_dir, '.Python') 1354 | 1355 | if os.path.exists(virtual_lib): 1356 | os.unlink(virtual_lib) 1357 | copyfile( 1358 | os.path.join(prefix, 'Python'), 1359 | virtual_lib) 1360 | 1361 | # And then change the install_name of the copied python executable 1362 | try: 1363 | mach_o_change(py_executable, 1364 | os.path.join(prefix, 'Python'), 1365 | '@executable_path/../.Python') 1366 | except: 1367 | e = sys.exc_info()[1] 1368 | logger.warn("Could not call mach_o_change: %s. " 1369 | "Trying to call install_name_tool instead." % e) 1370 | try: 1371 | call_subprocess( 1372 | ["install_name_tool", "-change", 1373 | os.path.join(prefix, 'Python'), 1374 | '@executable_path/../.Python', 1375 | py_executable]) 1376 | except: 1377 | logger.fatal("Could not call install_name_tool -- you must " 1378 | "have Apple's development tools installed") 1379 | raise 1380 | 1381 | # Some tools depend on pythonX.Y being present 1382 | py_executable_version = '%s.%s' % ( 1383 | sys.version_info[0], sys.version_info[1]) 1384 | if not py_executable.endswith(py_executable_version): 1385 | # symlinking pythonX.Y > python 1386 | pth = py_executable + '%s.%s' % ( 1387 | sys.version_info[0], sys.version_info[1]) 1388 | if os.path.exists(pth): 1389 | os.unlink(pth) 1390 | os.symlink('python', pth) 1391 | else: 1392 | # reverse symlinking python -> pythonX.Y (with --python) 1393 | pth = join(bin_dir, 'python') 1394 | if os.path.exists(pth): 1395 | os.unlink(pth) 1396 | os.symlink(os.path.basename(py_executable), pth) 1397 | 1398 | if sys.platform == 'win32' and ' ' in py_executable: 1399 | # There's a bug with subprocess on Windows when using a first 1400 | # argument that has a space in it. Instead we have to quote 1401 | # the value: 1402 | py_executable = '"%s"' % py_executable 1403 | # NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks 1404 | cmd = [py_executable, '-c', 'import sys;out=sys.stdout;' 1405 | 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))'] 1406 | logger.info('Testing executable with %s %s "%s"' % tuple(cmd)) 1407 | try: 1408 | proc = subprocess.Popen(cmd, 1409 | stdout=subprocess.PIPE) 1410 | proc_stdout, proc_stderr = proc.communicate() 1411 | except OSError: 1412 | e = sys.exc_info()[1] 1413 | if e.errno == errno.EACCES: 1414 | logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e)) 1415 | sys.exit(100) 1416 | else: 1417 | raise e 1418 | 1419 | proc_stdout = proc_stdout.strip().decode("utf-8") 1420 | proc_stdout = os.path.normcase(os.path.abspath(proc_stdout)) 1421 | norm_home_dir = os.path.normcase(os.path.abspath(home_dir)) 1422 | if hasattr(norm_home_dir, 'decode'): 1423 | norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding()) 1424 | if proc_stdout != norm_home_dir: 1425 | logger.fatal( 1426 | 'ERROR: The executable %s is not functioning' % py_executable) 1427 | logger.fatal( 1428 | 'ERROR: It thinks sys.prefix is %r (should be %r)' 1429 | % (proc_stdout, norm_home_dir)) 1430 | logger.fatal( 1431 | 'ERROR: virtualenv is not compatible with this system or executable') 1432 | if sys.platform == 'win32': 1433 | logger.fatal( 1434 | 'Note: some Windows users have reported this error when they ' 1435 | 'installed Python for "Only this user" or have multiple ' 1436 | 'versions of Python installed. Copying the appropriate ' 1437 | 'PythonXX.dll to the virtualenv Scripts/ directory may fix ' 1438 | 'this problem.') 1439 | sys.exit(100) 1440 | else: 1441 | logger.info('Got sys.prefix result: %r' % proc_stdout) 1442 | 1443 | pydistutils = os.path.expanduser('~/.pydistutils.cfg') 1444 | if os.path.exists(pydistutils): 1445 | logger.notify('Please make sure you remove any previous custom paths from ' 1446 | 'your %s file.' % pydistutils) 1447 | ## FIXME: really this should be calculated earlier 1448 | 1449 | fix_local_scheme(home_dir) 1450 | 1451 | return py_executable 1452 | 1453 | 1454 | def install_activate(home_dir, bin_dir, prompt=None): 1455 | home_dir = os.path.abspath(home_dir) 1456 | if sys.platform == 'win32' or is_jython and os._name == 'nt': 1457 | files = { 1458 | 'activate.bat': ACTIVATE_BAT, 1459 | 'deactivate.bat': DEACTIVATE_BAT, 1460 | 'activate.ps1': ACTIVATE_PS, 1461 | } 1462 | 1463 | # MSYS needs paths of the form /c/path/to/file 1464 | drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/')) 1465 | home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail) 1466 | 1467 | # Run-time conditional enables (basic) Cygwin compatibility 1468 | home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" % 1469 | (home_dir, home_dir_msys)) 1470 | files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh) 1471 | 1472 | else: 1473 | files = {'activate': ACTIVATE_SH} 1474 | 1475 | # suppling activate.fish in addition to, not instead of, the 1476 | # bash script support. 1477 | files['activate.fish'] = ACTIVATE_FISH 1478 | 1479 | # same for csh/tcsh support... 1480 | files['activate.csh'] = ACTIVATE_CSH 1481 | 1482 | files['activate_this.py'] = ACTIVATE_THIS 1483 | if hasattr(home_dir, 'decode'): 1484 | home_dir = home_dir.decode(sys.getfilesystemencoding()) 1485 | vname = os.path.basename(home_dir) 1486 | for name, content in files.items(): 1487 | content = content.replace('__VIRTUAL_PROMPT__', prompt or '') 1488 | content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname) 1489 | content = content.replace('__VIRTUAL_ENV__', home_dir) 1490 | content = content.replace('__VIRTUAL_NAME__', vname) 1491 | content = content.replace('__BIN_NAME__', os.path.basename(bin_dir)) 1492 | writefile(os.path.join(bin_dir, name), content) 1493 | 1494 | def install_distutils(home_dir): 1495 | distutils_path = change_prefix(distutils.__path__[0], home_dir) 1496 | mkdir(distutils_path) 1497 | ## FIXME: maybe this prefix setting should only be put in place if 1498 | ## there's a local distutils.cfg with a prefix setting? 1499 | home_dir = os.path.abspath(home_dir) 1500 | ## FIXME: this is breaking things, removing for now: 1501 | #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir 1502 | writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT) 1503 | writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False) 1504 | 1505 | def fix_local_scheme(home_dir): 1506 | """ 1507 | Platforms that use the "posix_local" install scheme (like Ubuntu with 1508 | Python 2.7) need to be given an additional "local" location, sigh. 1509 | """ 1510 | try: 1511 | import sysconfig 1512 | except ImportError: 1513 | pass 1514 | else: 1515 | if sysconfig._get_default_scheme() == 'posix_local': 1516 | local_path = os.path.join(home_dir, 'local') 1517 | if not os.path.exists(local_path): 1518 | os.mkdir(local_path) 1519 | for subdir_name in os.listdir(home_dir): 1520 | if subdir_name == 'local': 1521 | continue 1522 | os.symlink(os.path.abspath(os.path.join(home_dir, subdir_name)), \ 1523 | os.path.join(local_path, subdir_name)) 1524 | 1525 | def fix_lib64(lib_dir): 1526 | """ 1527 | Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y 1528 | instead of lib/pythonX.Y. If this is such a platform we'll just create a 1529 | symlink so lib64 points to lib 1530 | """ 1531 | if [p for p in distutils.sysconfig.get_config_vars().values() 1532 | if isinstance(p, basestring) and 'lib64' in p]: 1533 | logger.debug('This system uses lib64; symlinking lib64 to lib') 1534 | assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], ( 1535 | "Unexpected python lib dir: %r" % lib_dir) 1536 | lib_parent = os.path.dirname(lib_dir) 1537 | assert os.path.basename(lib_parent) == 'lib', ( 1538 | "Unexpected parent dir: %r" % lib_parent) 1539 | copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64')) 1540 | 1541 | def resolve_interpreter(exe): 1542 | """ 1543 | If the executable given isn't an absolute path, search $PATH for the interpreter 1544 | """ 1545 | if os.path.abspath(exe) != exe: 1546 | paths = os.environ.get('PATH', '').split(os.pathsep) 1547 | for path in paths: 1548 | if os.path.exists(os.path.join(path, exe)): 1549 | exe = os.path.join(path, exe) 1550 | break 1551 | if not os.path.exists(exe): 1552 | logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe)) 1553 | raise SystemExit(3) 1554 | if not is_executable(exe): 1555 | logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe)) 1556 | raise SystemExit(3) 1557 | return exe 1558 | 1559 | def is_executable(exe): 1560 | """Checks a file is executable""" 1561 | return os.access(exe, os.X_OK) 1562 | 1563 | ############################################################ 1564 | ## Relocating the environment: 1565 | 1566 | def make_environment_relocatable(home_dir): 1567 | """ 1568 | Makes the already-existing environment use relative paths, and takes out 1569 | the #!-based environment selection in scripts. 1570 | """ 1571 | home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1572 | activate_this = os.path.join(bin_dir, 'activate_this.py') 1573 | if not os.path.exists(activate_this): 1574 | logger.fatal( 1575 | 'The environment doesn\'t have a file %s -- please re-run virtualenv ' 1576 | 'on this environment to update it' % activate_this) 1577 | fixup_scripts(home_dir) 1578 | fixup_pth_and_egg_link(home_dir) 1579 | ## FIXME: need to fix up distutils.cfg 1580 | 1581 | OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3], 1582 | 'activate', 'activate.bat', 'activate_this.py'] 1583 | 1584 | def fixup_scripts(home_dir): 1585 | # This is what we expect at the top of scripts: 1586 | shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir)) 1587 | # This is what we'll put: 1588 | new_shebang = '#!/usr/bin/env python%s' % sys.version[:3] 1589 | activate = "import os; activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this" 1590 | if sys.platform == 'win32': 1591 | bin_suffix = 'Scripts' 1592 | else: 1593 | bin_suffix = 'bin' 1594 | bin_dir = os.path.join(home_dir, bin_suffix) 1595 | home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1596 | for filename in os.listdir(bin_dir): 1597 | filename = os.path.join(bin_dir, filename) 1598 | if not os.path.isfile(filename): 1599 | # ignore subdirs, e.g. .svn ones. 1600 | continue 1601 | f = open(filename, 'rb') 1602 | try: 1603 | try: 1604 | lines = f.read().decode('utf-8').splitlines() 1605 | except UnicodeDecodeError: 1606 | # This is probably a binary program instead 1607 | # of a script, so just ignore it. 1608 | continue 1609 | finally: 1610 | f.close() 1611 | if not lines: 1612 | logger.warn('Script %s is an empty file' % filename) 1613 | continue 1614 | if not lines[0].strip().startswith(shebang): 1615 | if os.path.basename(filename) in OK_ABS_SCRIPTS: 1616 | logger.debug('Cannot make script %s relative' % filename) 1617 | elif lines[0].strip() == new_shebang: 1618 | logger.info('Script %s has already been made relative' % filename) 1619 | else: 1620 | logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)' 1621 | % (filename, shebang)) 1622 | continue 1623 | logger.notify('Making script %s relative' % filename) 1624 | lines = [new_shebang+'\n', activate+'\n'] + lines[1:] 1625 | f = open(filename, 'wb') 1626 | f.write('\n'.join(lines).encode('utf-8')) 1627 | f.close() 1628 | 1629 | def fixup_pth_and_egg_link(home_dir, sys_path=None): 1630 | """Makes .pth and .egg-link files use relative paths""" 1631 | home_dir = os.path.normcase(os.path.abspath(home_dir)) 1632 | if sys_path is None: 1633 | sys_path = sys.path 1634 | for path in sys_path: 1635 | if not path: 1636 | path = '.' 1637 | if not os.path.isdir(path): 1638 | continue 1639 | path = os.path.normcase(os.path.abspath(path)) 1640 | if not path.startswith(home_dir): 1641 | logger.debug('Skipping system (non-environment) directory %s' % path) 1642 | continue 1643 | for filename in os.listdir(path): 1644 | filename = os.path.join(path, filename) 1645 | if filename.endswith('.pth'): 1646 | if not os.access(filename, os.W_OK): 1647 | logger.warn('Cannot write .pth file %s, skipping' % filename) 1648 | else: 1649 | fixup_pth_file(filename) 1650 | if filename.endswith('.egg-link'): 1651 | if not os.access(filename, os.W_OK): 1652 | logger.warn('Cannot write .egg-link file %s, skipping' % filename) 1653 | else: 1654 | fixup_egg_link(filename) 1655 | 1656 | def fixup_pth_file(filename): 1657 | lines = [] 1658 | prev_lines = [] 1659 | f = open(filename) 1660 | prev_lines = f.readlines() 1661 | f.close() 1662 | for line in prev_lines: 1663 | line = line.strip() 1664 | if (not line or line.startswith('#') or line.startswith('import ') 1665 | or os.path.abspath(line) != line): 1666 | lines.append(line) 1667 | else: 1668 | new_value = make_relative_path(filename, line) 1669 | if line != new_value: 1670 | logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename)) 1671 | lines.append(new_value) 1672 | if lines == prev_lines: 1673 | logger.info('No changes to .pth file %s' % filename) 1674 | return 1675 | logger.notify('Making paths in .pth file %s relative' % filename) 1676 | f = open(filename, 'w') 1677 | f.write('\n'.join(lines) + '\n') 1678 | f.close() 1679 | 1680 | def fixup_egg_link(filename): 1681 | f = open(filename) 1682 | link = f.readline().strip() 1683 | f.close() 1684 | if os.path.abspath(link) != link: 1685 | logger.debug('Link in %s already relative' % filename) 1686 | return 1687 | new_link = make_relative_path(filename, link) 1688 | logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link)) 1689 | f = open(filename, 'w') 1690 | f.write(new_link) 1691 | f.close() 1692 | 1693 | def make_relative_path(source, dest, dest_is_directory=True): 1694 | """ 1695 | Make a filename relative, where the filename is dest, and it is 1696 | being referred to from the filename source. 1697 | 1698 | >>> make_relative_path('/usr/share/something/a-file.pth', 1699 | ... '/usr/share/another-place/src/Directory') 1700 | '../another-place/src/Directory' 1701 | >>> make_relative_path('/usr/share/something/a-file.pth', 1702 | ... '/home/user/src/Directory') 1703 | '../../../home/user/src/Directory' 1704 | >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/') 1705 | './' 1706 | """ 1707 | source = os.path.dirname(source) 1708 | if not dest_is_directory: 1709 | dest_filename = os.path.basename(dest) 1710 | dest = os.path.dirname(dest) 1711 | dest = os.path.normpath(os.path.abspath(dest)) 1712 | source = os.path.normpath(os.path.abspath(source)) 1713 | dest_parts = dest.strip(os.path.sep).split(os.path.sep) 1714 | source_parts = source.strip(os.path.sep).split(os.path.sep) 1715 | while dest_parts and source_parts and dest_parts[0] == source_parts[0]: 1716 | dest_parts.pop(0) 1717 | source_parts.pop(0) 1718 | full_parts = ['..']*len(source_parts) + dest_parts 1719 | if not dest_is_directory: 1720 | full_parts.append(dest_filename) 1721 | if not full_parts: 1722 | # Special case for the current directory (otherwise it'd be '') 1723 | return './' 1724 | return os.path.sep.join(full_parts) 1725 | 1726 | 1727 | 1728 | ############################################################ 1729 | ## Bootstrap script creation: 1730 | 1731 | def create_bootstrap_script(extra_text, python_version=''): 1732 | """ 1733 | Creates a bootstrap script, which is like this script but with 1734 | extend_parser, adjust_options, and after_install hooks. 1735 | 1736 | This returns a string that (written to disk of course) can be used 1737 | as a bootstrap script with your own customizations. The script 1738 | will be the standard virtualenv.py script, with your extra text 1739 | added (your extra text should be Python code). 1740 | 1741 | If you include these functions, they will be called: 1742 | 1743 | ``extend_parser(optparse_parser)``: 1744 | You can add or remove options from the parser here. 1745 | 1746 | ``adjust_options(options, args)``: 1747 | You can change options here, or change the args (if you accept 1748 | different kinds of arguments, be sure you modify ``args`` so it is 1749 | only ``[DEST_DIR]``). 1750 | 1751 | ``after_install(options, home_dir)``: 1752 | 1753 | After everything is installed, this function is called. This 1754 | is probably the function you are most likely to use. An 1755 | example would be:: 1756 | 1757 | def after_install(options, home_dir): 1758 | subprocess.call([join(home_dir, 'bin', 'easy_install'), 1759 | 'MyPackage']) 1760 | subprocess.call([join(home_dir, 'bin', 'my-package-script'), 1761 | 'setup', home_dir]) 1762 | 1763 | This example immediately installs a package, and runs a setup 1764 | script from that package. 1765 | 1766 | If you provide something like ``python_version='2.4'`` then the 1767 | script will start with ``#!/usr/bin/env python2.4`` instead of 1768 | ``#!/usr/bin/env python``. You can use this when the script must 1769 | be run with a particular Python version. 1770 | """ 1771 | filename = __file__ 1772 | if filename.endswith('.pyc'): 1773 | filename = filename[:-1] 1774 | f = codecs.open(filename, 'r', encoding='utf-8') 1775 | content = f.read() 1776 | f.close() 1777 | py_exe = 'python%s' % python_version 1778 | content = (('#!/usr/bin/env %s\n' % py_exe) 1779 | + '## WARNING: This file is generated\n' 1780 | + content) 1781 | return content.replace('##EXT' 'END##', extra_text) 1782 | 1783 | ##EXTEND## 1784 | 1785 | def convert(s): 1786 | b = base64.b64decode(s.encode('ascii')) 1787 | return zlib.decompress(b).decode('utf-8') 1788 | 1789 | ##file site.py 1790 | SITE_PY = convert(""" 1791 | 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 1926 | YAowyJmdag/AGoXg/wBaZusT 1927 | """) 1928 | 1929 | ##file ez_setup.py 1930 | EZ_SETUP_PY = convert(""" 1931 | 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 1997 | BDaonX65d/fwEjNqlDjLVIvM9X+XVxF7 1998 | """) 1999 | 2000 | ##file distribute_setup.py 2001 | DISTRIBUTE_SETUP_PY = convert(""" 2002 | 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 2084 | """) 2085 | 2086 | ##file activate.sh 2087 | ACTIVATE_SH = convert(""" 2088 | eJytVVFv2jAQfs+vuIY+lGo06h5bMYmqSCC1UDWs09ZWwSQOseTYKHZI6bT/vnMSQtIA0rTmgRDf 2089 | 57vPd9+dOzCLmIKQcQpxqjQsKKSKBpAxHYGtZJr4FBZMOMTXbE00teE8TGQMC6Kic6sDG5mCT4SQ 2090 | GpJUANMQsIT6mm8sK6DbXXDWhd8W4JMKRTWsNoH0rXyhAwk1S5IHQMWaJVLEVGhYk4SRBacqR7EQ 2091 | nqEnwD71pne33tP4cfZ9cOc9DGYjG17hGnRERY40j1nu74NWCPq2konOgdVaQa21KbeH7CiNn7PR 2092 | dDKa3g/3kamMLUq7bS1ilekovSYKSZYpzauqIpliUgOqsR55wYCIAN5V9AWyiPkRRGRNgeALTb6M 2093 | Y2PWEdG5FkpXqAifcI6a0BKWyABLjP9CmZiPFUHRlFvVBcAP1I1MdWnWTCxLNw2gSRCcmuSCHxGx 2094 | pAoyFCAJzM8GjJgwLOpihcxp8CH1NwMXi96Txdcvd+Q9DR/d8XSyJ/n50XoJfP3mBHTtiJTzRqoO 2095 | FdS93FdJ97JVQgS2audeHi1aad5SKCBb63DytCN2gryQSB9sIUVAlU5S01D0A7cOuJSHsAWcfIje 2096 | M6ZtJ25D/7GweQs7SxLKUQmNpqv1bjO2ZdWo9m3Pq316nm2VSaifx2r1FKax6Mfyo4Z2PO9mPPEm 2097 | g/uh512VsHq7Vrx36jfZwhW0aCP8jHEOIWHcrNdRyqCMeo3+aLzSG8BzoUjhrGgIRCxIgG2yycim 2098 | i/78vIVwJMIcfZ3l6Uyv4QrVW/ntwvUcmMg7zNoJ6uBQONDC/caWmjRqXW40U0R4h0bWvNuxO7i5 2099 | G3oPj9P7h9nRiLmKK+Hm7uy3XR0LD1hKOOnD24EuaMN3HilXtOZ6jnmhgsQUXhqUX+x5Lm0TqRWk 2100 | A6b3GeE4fDD5OE5ggCsC58OS+eUdIxNWXg/lFkoh0np15ThZll28U40TZX2BU8dRMtQZSahDjBen 2101 | eZjnGsU5ut5L9mU+f4U9h6y8nB05aHe3sbxJyldtZJjaEs6IKm7Hvr3a4CwV0IuLBdso/1MG+ycM 2102 | 9f8c6P8+zPcNcszYX1+tk3g= 2103 | """) 2104 | 2105 | ##file activate.fish 2106 | ACTIVATE_FISH = convert(""" 2107 | eJyVVWFv2jAQ/c6vuBoqQVWC9nVSNVGVCaS2VC2rNLWVZZILWAs2sx1Yq/342SEJDrjbmgpK7PP5 2108 | 3bt3d22YLbmGlGcIq1wbmCPkGhPYcrMEEsGciwGLDd8wg1HK9ZLAWarkCtzvM+gujVl/Hgzcm15i 2109 | lkVSLXqtNrzKHGImhDSgcgHcQMIVxiZ7bbXSXFiPUkCClWuAfgJk9MvabbgyOctQbICJBBSaXAkw 2110 | EoRUK5ZBcQ3Yba6kWKEwpAX2aVtLjQZklvibsGGKs3mGurDiKRi0YfYFkA6dXl/Rx8n97Nvwmt4N 2111 | Z2MChZF7nKv+4he4ZTi2bNohhA1QJP+69ftsPL0dT29G5Pjqeu8QQL3xdxhNswrMO4i+Th7G9O5+ 2112 | enM3o9PH0f395MrDVKVMu1tcsunaimBtggBCrmrDCLpWZAsu6pXqWSsuTAqklod3z7N4Nm1ydGQP 2113 | i9q80xCwMnT4DWudz6EXDil4vMFYGWBF7uj2sUEk6TC12Dx9eiFwcgFESJHYZZU7feMeeBseMEuh 2114 | 2jsJo9nXRY3DfWxZ5cLh4EphxjZNeXvF1Ly91aoU5YEHQqn3SinZmx2JGTqFpBs1QTre8QGll5Nb 2115 | eju8GVlPpXkN1xOypcuutHb/oP8TDkQahuAVQsgefS8FUbW835o46dXkYXh5PSrVWXUOl3jX9jSw 2116 | OhHAhTbIEpCp7UOupTiuXR9aoEDlaDZLhJ1cor1O2qBtZoq9OLd5sjnydLV3z3RhU78HFRgulqNC 2117 | OTwbqJa9vkJFclQgZSjFFHAwpeIWhe2+h2HYANkKk3PYouv3IDeoFE9wd1TmCuRW7OgJ1bVXGHc7 2118 | z5WDL/WW36v2oi37CyVBak61+yPBA9C1qqGxzKQqZ0oPuocU9hpud0PIp8sDHkXR1HKktlzjuUWA 2119 | a0enFUyzOWZA4yXGP+ZMI3Tdt2OuqU/SO4q64526cPE0A7ZyW2PMbWZiZ5HamIZ2RcCKLXhcDl2b 2120 | vXL+eccQoRze2+02ekPDEtxEsVwNtEzNlikcMOdp8A7BT6f65VSDY9kjtD+HeZbb9C+5wZ4XZ9dC 2121 | CQXc+2A6MNP4DqLuqe7t0v4/gA5wfBRGKQGX6oMhUbWv0Bg8uLXoVn8AkYzUxg== 2122 | """) 2123 | 2124 | ##file activate.csh 2125 | ACTIVATE_CSH = convert(""" 2126 | eJx9U11v2jAUffevOA2o3ZBG9gxjGx2VVqmlVUUrTWMyTnLTWEocZDsg+uvnOEDDx5aHKLn3fFyf 2127 | 3HQwy6RBKnNCURmLiFAZSrCWNkNgykrHhEiqUMRWroSlfmyyAL1UlwXcY6/POvhVVoiFUqWFrhSk 2128 | RSI1xTbf1N0fmhwvQbTBRKxkQphIXOfCSHxJfCGJvr8WQub9uCy+9hkTuRQGCe08cWXJzdb9xh/u 2129 | Jvzl9mn2PL7jj+PZT1yM8BmXlzBkSa3ga0H3BBfUmEo5FE56Q2jKhMmGOOvy9HD/OGv7YOnOvrSj 2130 | YxsP/KeR7w6bVj3prnEzfdkaB/OLQS+onQJVqsSVdFUHQFvNk1Ra1eUmKeMr5tJ+9t5Sa8rFipTF 2131 | SmgpopxMn7W4hw6MnU6FgPPWK+eBR53m54LwEbPDb9Dihpxf3075dHx/w/lgiz4j5jNyck3ADiJT 2132 | fGiN0QDcJD6k4CNsRorBXbWW8+ZKFIQRznEY5YY8uFZdRMKQRx9MGiww8vS2eH11YJYUS5G7RTeE 2133 | tNQYu4pCIV5lvN33UksybQoRMmuXgzBcr9f9N7IioVW95aEpU7sWmkJRq4R70tFB3secL5zHmYHn 2134 | i4Un70/3X5WjwzZMlciUNff39a5T/N3difzB/qM0y71r7H5Wv4DubrNS4VPRvDPW/FmM/QUd6WEa 2135 | """) 2136 | 2137 | ##file activate.bat 2138 | ACTIVATE_BAT = convert(""" 2139 | eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8 2140 | qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug 2141 | sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU 2142 | ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu 2143 | """) 2144 | 2145 | ##file deactivate.bat 2146 | DEACTIVATE_BAT = convert(""" 2147 | eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q 2148 | FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL 2149 | i2dASrm4rFz9XLgAwJNbyQ== 2150 | """) 2151 | 2152 | ##file activate.ps1 2153 | ACTIVATE_PS = convert(""" 2154 | eJylWdmS40Z2fVeE/oHT6rCloNUEAXDThB6wAyQAEjsB29GBjdgXYiWgmC/zgz/Jv+AEWNVd3S2N 2155 | xuOKYEUxM+/Jmzfvcm7W//zXf/+wUMOoXtyi1F9kbd0sHH/hFc2iLtrK9b3FrSqyxaVQwr8uhqJd 2156 | uHaeg9mqzRdR8/13Pyy8qPLdJh0+LMhi0QCoXxYfFh9WtttEnd34H8p6/f1300KauwrULws39e18 2157 | 0ZaLNm9rgN/ZVf3h++/e124Vlc0vKsspHy+Yyi5+XbzPhijvCtduoiL/kA1ukWV27n0o7Sb8LIFj 2158 | CvWR5GQgUJdp1Pw8TS9+rPy6SDv/+e3d+0+4qw8f3v20+PliV37efEYBAB9FTKC+RHn/Cfxn3rdv 2159 | 00Fube5O+iyCtHDs9BfPfz3q4sfFv9d91Ljhfy7ei0VO+nVTtdOkv/jpt0l2AX6iG1jXgKnnDuD4 2160 | ke2k/i8fzzz5UedkVcP4pwF+Wvz2FJl+3vt598urXf5Y6LNA5WcFOP7r0sW7b9a+W/xcu0Xpv5zk 2161 | Kfq3P9Dz9di/fCxS72MXVU1rpx9L4Bxl85Wmn5a+zP76Zuh3pL9ROWr87PN+//GHIl+oOtvn9XSU 2162 | qH+p0gQBFnx1uV+JLH5O5zv+PXW+WepXVVHZT0+oQezkIATcIm+ivPV/z5J/+cYj3ir4w0Lx09vC 2163 | e5n/y5/Y5LPPfdrqb88ga/PabxZRVfmp39l588m/6u+/e+OpP+dF7n1WZpJ9//Z4v372fDDz9eHB 2164 | 7Juvs/BLMHzrxL9+9twXpJfhd1/DrpQ5Euu/vlss3wp9HXC/54C/Ld69m6zwdx3tC0d8daSv0V8B 2165 | n4b9YYF53sJelJV/ix6LZspw/sJtqyl5LJ5r/23htA1Imfm/gt9R7dqVB1LjhydAX4Gb+zksQF59 2166 | 9+P7H//U+376afFuvh2/T6P85Xr/5c8C6OXyFY4BGuN+EE0+GeR201b+wkkLN5mmBY5TfMw8ngqL 2167 | CztXxCSXKMCYrRIElWkEJlEPYsSOeKBVZCAQTKBhApMwRFQzmCThE0YQu2CdEhgjbgmk9GluHpfR 2168 | /hhwJCZhGI5jt5FsAkOrObVyE6g2y1snyhMGFlDY1x+BoHpCMulTj5JYWNAYJmnKpvLxXgmQ8az1 2169 | 4fUGxxcitMbbhDFcsiAItg04E+OSBIHTUYD1HI4FHH4kMREPknuYRMyhh3AARWMkfhCketqD1CWJ 2170 | mTCo/nhUScoQcInB1hpFhIKoIXLo5jLpwFCgsnLCx1QlEMlz/iFEGqzH3vWYcpRcThgWnEKm0QcS 2171 | rA8ek2a2IYYeowUanOZOlrbWSJUC4c7y2EMI3uJPMnMF/SSXdk6E495VLhzkWHps0rOhKwqk+xBI 2172 | DhJirhdUCTamMfXz2Hy303hM4DFJ8QL21BcPBULR+gcdYxoeiDqOFSqpi5B5PUISfGg46gFZBPo4 2173 | jdh8lueaWuVSMTURfbAUnLINr/QYuuYoMQV6l1aWxuZVTjlaLC14UzqZ+ziTGDzJzhiYoPLrt3uI 2174 | tXkVR47kAo09lo5BD76CH51cTt1snVpMOttLhY93yxChCQPI4OBecS7++h4p4Bdn4H97bJongtPk 2175 | s9gQnXku1vzsjjmX4/o4YUDkXkjHwDg5FXozU0fW4y5kyeYW0uJWlh536BKr0kMGjtzTkng6Ep62 2176 | uTWnQtiIqKnEsx7e1hLtzlXs7Upw9TwEnp0t9yzCGgUJIZConx9OHJArLkRYW0dW42G9OeR5Nzwk 2177 | yk1mX7du5RGHT7dka7N3AznmSif7y6tuKe2N1Al/1TUPRqH6E2GLVc27h9IptMLkCKQYRqPQJgzV 2178 | 2m6WLsSipS3v3b1/WmXEYY1meLEVIU/arOGVkyie7ZsH05ZKpjFW4cpY0YkjySpSExNG2TS8nnJx 2179 | nrQmWh2WY3cP1eISP9wbaVK35ZXc60yC3VN/j9n7UFoK6zvjSTE2+Pvz6Mx322rnftfP8Y0XKIdv 2180 | Qd7AfK0nexBTMqRiErvCMa3Hegpfjdh58glW2oNMsKeAX8x6YJLZs9K8/ozjJkWL+JmECMvhQ54x 2181 | 9rsTHwcoGrDi6Y4I+H7yY4/rJVPAbYymUH7C2D3uiUS3KQ1nrCAUkE1dJMneDQIJMQQx5SONxoEO 2182 | OEn1/Ig1eBBUeEDRuOT2WGGGE4bNypBLFh2PeIg3bEbg44PHiqNDbGIQm50LW6MJU62JHCGBrmc9 2183 | 2F7WBJrrj1ssnTAK4sxwRgh5LLblhwNAclv3Gd+jC/etCfyfR8TMhcWQz8TBIbG8IIyAQ81w2n/C 2184 | mHWAwRzxd3WoBY7BZnsqGOWrOCKwGkMMNfO0Kci/joZgEocLjNnzgcmdehPHJY0FudXgsr+v44TB 2185 | I3jnMGnsK5veAhgi9iXGifkHMOC09Rh9cAw9sQ0asl6wKMk8mpzFYaaDSgG4F0wisQDDBRpjCINg 2186 | FIxhlhQ31xdSkkk6odXZFpTYOQpOOgw9ugM2cDQ+2MYa7JsEirGBrOuxsQy5nPMRdYjsTJ/j1iNw 2187 | FeSt1jY2+dd5yx1/pzZMOQXUIDcXeAzR7QlDRM8AMkUldXOmGmvYXPABjxqkYKO7VAY6JRU7kpXr 2188 | +Epu2BU3qFFXClFi27784LrDZsJwbNlDw0JzhZ6M0SMXE4iBHehCpHVkrQhpTFn2dsvsZYkiPEEB 2189 | GSEAwdiur9LS1U6P2U9JhGp4hnFpJo4FfkdJHcwV6Q5dV1Q9uNeeu7rV8PAjwdFg9RLtroifOr0k 2190 | uOiRTo/obNPhQIf42Fr4mtThWoSjitEdAmFW66UCe8WFjPk1YVNpL9srFbond7jrLg8tqAasIMpy 2191 | zkH0SY/6zVAwJrEc14zt14YRXdY+fcJ4qOd2XKB0/Kghw1ovd11t2o+zjt+txndo1ZDZ2T+uMVHT 2192 | VSXhedBAHoJIID9xm6wPQI3cXY+HR7vxtrJuCKh6kbXaW5KkVeJsdsjqsYsOwYSh0w5sMbu7LF8J 2193 | 5T7U6LJdiTx+ca7RKlulGgS5Z1JSU2Llt32cHFipkaurtBrvNX5UtvNZjkufZ/r1/XyLl6yOpytL 2194 | Km8Fn+y4wkhlqZP5db0rooqy7xdL4wxzFVTX+6HaxuQJK5E5B1neSSovZ9ALB8091dDbbjVxhWNY 2195 | Ve5hn1VnI9OF0wpvaRm7SZuC1IRczwC7GnkhPt3muHV1YxUJfo+uh1sYnJy+vI0ZwuPV2uqWJYUH 2196 | bmBsi1zmFSxHrqwA+WIzLrHkwW4r+bad7xbOzJCnKIa3S3YvrzEBK1Dc0emzJW+SqysQfdEDorQG 2197 | 9ZJlbQzEHQV8naPaF440YXzJk/7vHGK2xwuP+Gc5xITxyiP+WQ4x18oXHjFzCBy9kir1EFTAm0Zq 2198 | LYwS8MpiGhtfxiBRDXpxDWxk9g9Q2fzPPAhS6VFDAc/aiNGatUkPtZIStZFQ1qD0IlJa/5ZPAi5J 2199 | ySp1ETDomZMnvgiysZSBfMikrSDte/K5lqV6iwC5q7YN9I1dBZXUytDJNqU74MJsUyNNLAPopWK3 2200 | tzmLkCiDyl7WQnj9sm7Kd5kzgpoccdNeMw/6zPVB3pUwMgi4C7hj4AMFAf4G27oXH8NNT9zll/sK 2201 | S6wVlQwazjxWKWy20ZzXb9ne8ngGalPBWSUSj9xkc1drsXkZ8oOyvYT3e0rnYsGwx85xZB9wKeKg 2202 | cJKZnamYwiaMymZvzk6wtDUkxmdUg0mPad0YHtvzpjEfp2iMxvORhnx0kCVLf5Qa43WJsVoyfEyI 2203 | pzmf8ruM6xBr7dnBgzyxpqXuUPYaKahOaz1LrxNkS/Q3Ae5AC+xl6NbxAqXXlzghZBZHmOrM6Y6Y 2204 | ctAkltwlF7SKEsShjVh7QHuxMU0a08/eiu3x3M+07OijMcKFFltByXrpk8w+JNnZpnp3CfgjV1Ax 2205 | gUYCnWwYow42I5wHCcTzLXK0hMZN2DrPM/zCSqe9jRSlJnr70BPE4+zrwbk/xVIDHy2FAQyHoomT 2206 | Tt5jiM68nBQut35Y0qLclLiQrutxt/c0OlSqXAC8VrxW97lGoRWzhOnifE2zbF05W4xuyhg7JTUL 2207 | aqJ7SWDywhjlal0b+NLTpERBgnPW0+Nw99X2Ws72gOL27iER9jgzj7Uu09JaZ3n+hmCjjvZpjNst 2208 | vOWWTbuLrg+/1ltX8WpPauEDEvcunIgTxuMEHweWKCx2KQ9DU/UKdO/3za4Szm2iHYL+ss9AAttm 2209 | gZHq2pkUXFbV+FiJCKrpBms18zH75vax5jSo7FNunrVWY3Chvd8KKnHdaTt/6ealwaA1x17yTlft 2210 | 8VBle3nAE+7R0MScC3MJofNCCkA9PGKBgGMYEwfB2QO5j8zUqa8F/EkWKCzGQJ5EZ05HTly1B01E 2211 | z813G5BY++RZ2sxbQS8ZveGPJNabp5kXAeoign6Tlt5+L8i5ZquY9+S+KEUHkmYMRFBxRrHnbl2X 2212 | rVemKnG+oB1yd9+zT+4c43jQ0wWmQRR6mTCkY1q3VG05Y120ZzKOMBe6Vy7I5Vz4ygPB3yY4G0FP 2213 | 8RxiMx985YJPXsgRU58EuHj75gygTzejP+W/zKGe78UQN3yOJ1aMQV9hFH+GAfLRsza84WlPLAI/ 2214 | 9G/5JdcHftEfH+Y3/fHUG7/o8bv98dzzy3e8S+XCvgqB+VUf7sH0yDHpONdbRE8tAg9NWOzcTJ7q 2215 | TuAxe/AJ07c1Rs9okJvl1/0G60qvbdDzz5zO0FuPFQIHNp9y9Bd1CufYVx7dB26mAxwa8GMNrN/U 2216 | oGbNZ3EQ7inLzHy5tRg9AXJrN8cB59cCUBeCiVO7zKM0jU0MamhnRThkg/NMmBOGb6StNeD9tDfA 2217 | 7czsAWopDdnGoXUHtA+s/k0vNPkBcxEI13jVd/axp85va3LpwGggXXWw12Gwr/JGAH0b8CPboiZd 2218 | QO1l0mk/UHukud4C+w5uRoNzpCmoW6GbgbMyaQNkga2pQINB18lOXOCJzSWPFOhZcwzdgrsQnne7 2219 | nvjBi+7cP2BbtBeDOW5uOLGf3z94FasKIguOqJl+8ss/6Kumns4cuWbqq5592TN/RNIbn5Qo6qbi 2220 | O4F0P9txxPAwagqPlftztO8cWBzdN/jz3b7GD6JHYP/Zp4ToAMaA74M+EGSft3hEGMuf8EwjnTk/ 2221 | nz/P7SLipB/ogQ6xNX0fDqNncMCfHqGLCMM0ZzFa+6lPJYQ5p81vW4HkCvidYf6kb+P/oB965g8K 2222 | C6uR0rdjX1DNKc5pOSTquI8uQ6KXxYaKBn+30/09tK4kMpJPgUIQkbENEPbuezNPPje2Um83SgyX 2223 | GTCJb6MnGVIpgncdQg1qz2bvPfxYD9fewCXDomx9S+HQJuX6W3VAL+v5WZMudRQZk9ZdOk6GIUtC 2224 | PqEb/uwSIrtR7/edzqgEdtpEwq7p2J5OQV+RLrmtTvFwFpf03M/VrRyTZ73qVod7v7Jh2Dwe5J25 2225 | JqFOU2qEu1sP+CRotklediycKfLjeIZzjJQsvKmiGSNQhxuJpKa+hoWUizaE1PuIRGzJqropwgVB 2226 | oo1hr870MZLgnXF5ZIpr6mF0L8aSy2gVnTAuoB4WEd4d5NPVC9TMotYXERKlTcwQ2KiB/C48AEfH 2227 | Qbyq4CN8xTFnTvf/ebOc3isnjD95s0QF0nx9s+y+zMmz782xL0SgEmRpA3x1w1Ff9/74xcxKEPdS 2228 | IEFTz6GgU0+BK/UZ5Gwbl4gZwycxEw+Kqa5QmMkh4OzgzEVPnDAiAOGBFaBW4wkDmj1G4RyElKgj 2229 | NlLCq8zsp085MNh/+R4t1Q8yxoSv8PUpTt7izZwf2BTHZZ3pIZpUIpuLkL1nNL6sYcHqcKm237wp 2230 | T2+RCjgXweXd2Zp7ZM8W6dG5bZsqo0nrJBTx8EC0+CQQdzEGnabTnkzofu1pYkWl4E7XSniECdxy 2231 | vLYavPMcL9LW5SToJFNnos+uqweOHriUZ1ntIYZUonc7ltEQ6oTRtwOHNwez2sVREskHN+bqG3ua 2232 | eaEbJ8XpyO8CeD9QJc8nbLP2C2R3A437ISUNyt5Yd0TbDNcl11/DSsOzdbi/VhCC0KE6v1vqVNkq 2233 | 45ZnG6fiV2NwzInxCNth3BwL0+8814jE6+1W1EeWtpWbSZJOJNYXmWRXa7vLnAljE692eHjZ4y5u 2234 | y1u63De0IzKca7As48Z3XshVF+3XiLNz0JIMh/JOpbiNLlMi672uO0wYzOCZjRxcxj3D+gVenGIE 2235 | MvFUGGXuRps2RzMcgWIRolHXpGUP6sMsQt1hspUBnVKUn/WQj2u6j3SXd9Xz0QtEzoM7qTu5y7gR 2236 | q9gNNsrlEMLdikBt9bFvBnfbUIh6voTw7eDsyTmPKUvF0bHqWLbHe3VRHyRZnNeSGKsB73q66Vsk 2237 | taxWYmwz1tYVFG/vOQhlM0gUkyvIab3nv2caJ1udU1F3pDMty7stubTE4OJqm0i0ECfrJIkLtraC 2238 | HwRWKzlqpfhEIqYH09eT9WrOhQyt8YEoyBlnXtAT37WHIQ03TIuEHbnRxZDdLun0iok9PUC79prU 2239 | m5beZzfQUelEXnhzb/pIROKx3F7qCttYIFGh5dXNzFzID7u8vKykA8Uejf7XXz//S4nKvW//ofS/ 2240 | QastYw== 2241 | """) 2242 | 2243 | ##file distutils-init.py 2244 | DISTUTILS_INIT = convert(""" 2245 | eJytV92L4zYQf9dfMU0ottuse7RvC6FQrg8Lxz2Ugz4si9HacqKuIxlJ2ST313fG8odkO9d7qGFB 2246 | keZLv/nNjFaeWm0caMukX9nbuLxwo6Q6WBg2dFvqSsB2WEgLSjvg8C6NO/NGqHc46erciB1YDRcB 2247 | JVdwtijpwGmoparAHQVYVzXylUH0beGpc8OV+wG+oLo2b6AVtLf2tkM19HY6WwevAj16N7jLHRhh 2248 | ZSUsSEXGF1bR00N7c0etfkEtWUtRPVzzW/4VKmlE6bS5MYZLxU8C9ghF3nJ3zPsdOrLu7GRjC9oP 2249 | JP7RUqUz8dRDkxdFLRtRFNkOktFAkjFZj+pKmxMt0thBBvtFEOlCZ7SfPXYXHnKV0yIdMdh8QbSD 2250 | 7IyuoOXlGz8glA5+tMDbVnBjKUkIrwcSLAHS6JI7iWng1m/erBOnydDvm4yJxgofRtFdoShyqaww 2251 | Lv2wg9ntOjFxFSUiJSb4OixjUUSuKKSSDs21tyTLciN4lWYZY7XRQQjQ05M2dhRgqVUtD4w5c/Nh 2252 | vXIrrDMIEBPXUrQOPuPd/jRGm7kA5hcXjG23CJErj/B6lk1ViKuDKT6otLAqcfCm9AWO+IfAHYTr 2253 | EEK+2YBa3tCRmHxB/uuLhQeqhyM3FVHFw0oimAajz32JdM5FRdfJWyNqecV7I3u63w13NTKBmJKg 2254 | 0d9+Tfw1YlzyUp9OXFX5dIUeqWkDs6pxOW50ZsqGWzsJpZFETzj6KlFTTfNGfhWFbokmFlIrmjoQ 2255 | oo/ixt0coTHc3ApEx1L3+KyVeJwVLKyI7uH5JRITDZqUFlmG7aIU6UJlF6Q0+z4Xi73cto10A0Wt 2256 | aLPIDvumwaACIo5T/pDHTeGTuoPNJ+TLJottR4jnc4w9xMtg1tO/mvTxR9F3Ul8Gs92AOfvpsCuO 2257 | yQ2terraR8YodGr0ha/Crk8RvCSWf5SUktczXSNfSLGeUPFuSKi6q489rDoJYPFdqpgKdta1F50m 2258 | QK0+JN7INmjW4ooCNp3b7cPajrEFaV/Ijgnbwt80t7BnlLxpfLkL84CD0oC/ENCFWF86GIOfTVjt 2259 | rbbymkyEJp3u9v302mCrjO6y8Q137NCrSqs6c6kFjQcGR4JZEHUnLi0dpbHQFAv2MeyGOFFw6DQY 2260 | RNrBuOwfJJMLVdmLxPGXzCJOVmrc58OIk34XKalnLD6ioaeqdCV8I9zZKC/GvoO4iM6SzHGVjGNp 2261 | Vio4NQr/OsFZV1IbGgTz+KgrjvFwppfSSChsK0p835R7ZJ9Pzp46bI8Ngug3l5233++ch90pBGMZ 2262 | bOx0cJmxe0Hio6jSZVH09bt+yO7dP4RmprtAEhvxPSTp3XkXSTxcIkkjpsJhTad3kQ2FgJru/wj1 2263 | Iqo4pv8AHiXuAx8crgM/Q3KmOwHfH79zP0ojU8HZCvTBafoTN4ehp3bY9PZWvPSyI/7fehbRh9HS 2264 | XF7rY/E4brpxPOrF74wxKHrXli7rUp18evrj49NfSffPELaxUSjuSeP286DwgtEMcW1xKr/he4/6 2265 | IQ6FUXP+0gkioHY5iwC9Eyx3HKO7af0zPPe+XyLnZDUk46jB7uZthV8rp+wuKxYMCxnzL9Vk9s4= 2266 | """) 2267 | 2268 | ##file distutils.cfg 2269 | DISTUTILS_CFG = convert(""" 2270 | eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH 2271 | xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg 2272 | 9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q= 2273 | """) 2274 | 2275 | ##file activate_this.py 2276 | ACTIVATE_THIS = convert(""" 2277 | eJyNU01v2zAMvetXEB4K21jmDOstQA4dMGCHbeihlyEIDMWmG62yJEiKE//7kXKdpN2KzYBt8euR 2278 | fKSyLPs8wiEo8wh4wqZTGou4V6Hm0wJa1cSiTkJdr8+GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe 2279 | 5a3p0cRKiAe2NtLADikftnDco0ko/SFEVgEZ8aRC5GLux7i3BpSJ6J1H+i7A2CjiHq9z7JRZuuQq 2280 | siwTIvpxJYCeuWaBpwZdhB+yxy/eWz+ZvVSU8C4E9FFZkyxFsvCT/ZzL8gcz9aXVE14Yyp2M+2W0 2281 | y7n5mp0qN+avKXvbsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCZN9UzlJr+/e/iab8WfqsmPI6pWeUPd 2282 | FrMsd4H/55poeO9n54COhUs+sZNEzNtg/wanpjpuqHJaxs76HtZryI/K3H7KJ/KDIhqcbJ7kI4ar 2283 | XL+sMgXnX0D+Te2Iy5xdP8yueSlQB/x/ED2BTAtyE3K4SYUN6AMNfbO63f4lBW3bUJPbTL+mjSxS 2284 | PyRfJkZRgj+VbFv+EzHFi5pKwUEepa4JslMnwkowSRCXI+m5XvEOvtuBrxHdhLalG0JofYBok6qj 2285 | YdN2dEngUlbC4PG60M1WEN0piu7Nq7on0mgyyUw3iV1etLo6r/81biWdQ9MWHFaePWZYaq+nmp+t 2286 | s3az+sj7eA0jfgPfeoN1 2287 | """) 2288 | 2289 | MH_MAGIC = 0xfeedface 2290 | MH_CIGAM = 0xcefaedfe 2291 | MH_MAGIC_64 = 0xfeedfacf 2292 | MH_CIGAM_64 = 0xcffaedfe 2293 | FAT_MAGIC = 0xcafebabe 2294 | BIG_ENDIAN = '>' 2295 | LITTLE_ENDIAN = '<' 2296 | LC_LOAD_DYLIB = 0xc 2297 | maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint') 2298 | 2299 | 2300 | class fileview(object): 2301 | """ 2302 | A proxy for file-like objects that exposes a given view of a file. 2303 | Modified from macholib. 2304 | """ 2305 | 2306 | def __init__(self, fileobj, start=0, size=maxint): 2307 | if isinstance(fileobj, fileview): 2308 | self._fileobj = fileobj._fileobj 2309 | else: 2310 | self._fileobj = fileobj 2311 | self._start = start 2312 | self._end = start + size 2313 | self._pos = 0 2314 | 2315 | def __repr__(self): 2316 | return '' % ( 2317 | self._start, self._end, self._fileobj) 2318 | 2319 | def tell(self): 2320 | return self._pos 2321 | 2322 | def _checkwindow(self, seekto, op): 2323 | if not (self._start <= seekto <= self._end): 2324 | raise IOError("%s to offset %d is outside window [%d, %d]" % ( 2325 | op, seekto, self._start, self._end)) 2326 | 2327 | def seek(self, offset, whence=0): 2328 | seekto = offset 2329 | if whence == os.SEEK_SET: 2330 | seekto += self._start 2331 | elif whence == os.SEEK_CUR: 2332 | seekto += self._start + self._pos 2333 | elif whence == os.SEEK_END: 2334 | seekto += self._end 2335 | else: 2336 | raise IOError("Invalid whence argument to seek: %r" % (whence,)) 2337 | self._checkwindow(seekto, 'seek') 2338 | self._fileobj.seek(seekto) 2339 | self._pos = seekto - self._start 2340 | 2341 | def write(self, bytes): 2342 | here = self._start + self._pos 2343 | self._checkwindow(here, 'write') 2344 | self._checkwindow(here + len(bytes), 'write') 2345 | self._fileobj.seek(here, os.SEEK_SET) 2346 | self._fileobj.write(bytes) 2347 | self._pos += len(bytes) 2348 | 2349 | def read(self, size=maxint): 2350 | assert size >= 0 2351 | here = self._start + self._pos 2352 | self._checkwindow(here, 'read') 2353 | size = min(size, self._end - here) 2354 | self._fileobj.seek(here, os.SEEK_SET) 2355 | bytes = self._fileobj.read(size) 2356 | self._pos += len(bytes) 2357 | return bytes 2358 | 2359 | 2360 | def read_data(file, endian, num=1): 2361 | """ 2362 | Read a given number of 32-bits unsigned integers from the given file 2363 | with the given endianness. 2364 | """ 2365 | res = struct.unpack(endian + 'L' * num, file.read(num * 4)) 2366 | if len(res) == 1: 2367 | return res[0] 2368 | return res 2369 | 2370 | 2371 | def mach_o_change(path, what, value): 2372 | """ 2373 | Replace a given name (what) in any LC_LOAD_DYLIB command found in 2374 | the given binary with a new name (value), provided it's shorter. 2375 | """ 2376 | 2377 | def do_macho(file, bits, endian): 2378 | # Read Mach-O header (the magic number is assumed read by the caller) 2379 | cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6) 2380 | # 64-bits header has one more field. 2381 | if bits == 64: 2382 | read_data(file, endian) 2383 | # The header is followed by ncmds commands 2384 | for n in range(ncmds): 2385 | where = file.tell() 2386 | # Read command header 2387 | cmd, cmdsize = read_data(file, endian, 2) 2388 | if cmd == LC_LOAD_DYLIB: 2389 | # The first data field in LC_LOAD_DYLIB commands is the 2390 | # offset of the name, starting from the beginning of the 2391 | # command. 2392 | name_offset = read_data(file, endian) 2393 | file.seek(where + name_offset, os.SEEK_SET) 2394 | # Read the NUL terminated string 2395 | load = file.read(cmdsize - name_offset) 2396 | load = load[:load.index('\0')] 2397 | # If the string is what is being replaced, overwrite it. 2398 | if load == what: 2399 | file.seek(where + name_offset, os.SEEK_SET) 2400 | file.write(value + '\0') 2401 | # Seek to the next command 2402 | file.seek(where + cmdsize, os.SEEK_SET) 2403 | 2404 | def do_file(file, offset=0, size=maxint): 2405 | file = fileview(file, offset, size) 2406 | # Read magic number 2407 | magic = read_data(file, BIG_ENDIAN) 2408 | if magic == FAT_MAGIC: 2409 | # Fat binaries contain nfat_arch Mach-O binaries 2410 | nfat_arch = read_data(file, BIG_ENDIAN) 2411 | for n in range(nfat_arch): 2412 | # Read arch header 2413 | cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5) 2414 | do_file(file, offset, size) 2415 | elif magic == MH_MAGIC: 2416 | do_macho(file, 32, BIG_ENDIAN) 2417 | elif magic == MH_CIGAM: 2418 | do_macho(file, 32, LITTLE_ENDIAN) 2419 | elif magic == MH_MAGIC_64: 2420 | do_macho(file, 64, BIG_ENDIAN) 2421 | elif magic == MH_CIGAM_64: 2422 | do_macho(file, 64, LITTLE_ENDIAN) 2423 | 2424 | assert(len(what) >= len(value)) 2425 | do_file(open(path, 'r+b')) 2426 | 2427 | 2428 | if __name__ == '__main__': 2429 | main() 2430 | 2431 | ## TODO: 2432 | ## Copy python.exe.manifest 2433 | ## Monkeypatch distutils.sysconfig 2434 | --------------------------------------------------------------------------------