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. 7virtualenv_version = "1.7" 8 9import base64 10import sys 11import os 12import optparse 13import re 14import shutil 15import logging 16import tempfile 17import zlib 18import errno 19import distutils.sysconfig 20from distutils.util import strtobool 21 22try: 23 import subprocess 24except ImportError: 25 if sys.version_info <= (2, 3): 26 print('ERROR: %s' % sys.exc_info()[1]) 27 print('ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.') 28 print('If you copy subprocess.py from a newer version of Python this script will probably work') 29 sys.exit(101) 30 else: 31 raise 32try: 33 set 34except NameError: 35 from sets import Set as set 36try: 37 basestring 38except NameError: 39 basestring = str 40 41try: 42 import ConfigParser 43except ImportError: 44 import configparser as ConfigParser 45 46join = os.path.join 47py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1]) 48 49is_jython = sys.platform.startswith('java') 50is_pypy = hasattr(sys, 'pypy_version_info') 51is_win = (sys.platform == 'win32') 52abiflags = getattr(sys, 'abiflags', '') 53 54user_dir = os.path.expanduser('~') 55if sys.platform == 'win32': 56 user_dir = os.environ.get('APPDATA', user_dir) # Use %APPDATA% for roaming 57 default_storage_dir = os.path.join(user_dir, 'virtualenv') 58else: 59 default_storage_dir = os.path.join(user_dir, '.virtualenv') 60default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini') 61 62if is_pypy: 63 expected_exe = 'pypy' 64elif is_jython: 65 expected_exe = 'jython' 66else: 67 expected_exe = 'python' 68 69 70REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath', 71 'fnmatch', 'locale', 'encodings', 'codecs', 72 'stat', 'UserDict', 'readline', 'copy_reg', 'types', 73 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile', 74 'zlib'] 75 76REQUIRED_FILES = ['lib-dynload', 'config'] 77 78majver, minver = sys.version_info[:2] 79if majver == 2: 80 if minver >= 6: 81 REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc']) 82 if minver >= 7: 83 REQUIRED_MODULES.extend(['_weakrefset']) 84 if minver <= 3: 85 REQUIRED_MODULES.extend(['sets', '__future__']) 86elif majver == 3: 87 # Some extra modules are needed for Python 3, but different ones 88 # for different versions. 89 REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io', 90 '_weakrefset', 'copyreg', 'tempfile', 'random', 91 '__future__', 'collections', 'keyword', 'tarfile', 92 'shutil', 'struct', 'copy']) 93 if minver >= 2: 94 REQUIRED_FILES[-1] = 'config-%s' % majver 95 if minver == 3: 96 # The whole list of 3.3 modules is reproduced below - the current 97 # uncommented ones are required for 3.3 as of now, but more may be 98 # added as 3.3 development continues. 99 REQUIRED_MODULES.extend([ 100 #"aifc", 101 #"antigravity", 102 #"argparse", 103 #"ast", 104 #"asynchat", 105 #"asyncore", 106 "base64", 107 #"bdb", 108 #"binhex", 109 "bisect", 110 #"calendar", 111 #"cgi", 112 #"cgitb", 113 #"chunk", 114 #"cmd", 115 #"codeop", 116 #"code", 117 #"colorsys", 118 #"_compat_pickle", 119 #"compileall", 120 #"concurrent", 121 #"configparser", 122 #"contextlib", 123 #"cProfile", 124 #"crypt", 125 #"csv", 126 #"ctypes", 127 #"curses", 128 #"datetime", 129 #"dbm", 130 #"decimal", 131 #"difflib", 132 #"dis", 133 #"doctest", 134 #"dummy_threading", 135 "_dummy_thread", 136 #"email", 137 #"filecmp", 138 #"fileinput", 139 #"formatter", 140 #"fractions", 141 #"ftplib", 142 #"functools", 143 #"getopt", 144 #"getpass", 145 #"gettext", 146 #"glob", 147 #"gzip", 148 "hashlib", 149 "heapq", 150 "hmac", 151 #"html", 152 #"http", 153 #"idlelib", 154 #"imaplib", 155 #"imghdr", 156 #"importlib", 157 #"inspect", 158 #"json", 159 #"lib2to3", 160 #"logging", 161 #"macpath", 162 #"macurl2path", 163 #"mailbox", 164 #"mailcap", 165 #"_markupbase", 166 #"mimetypes", 167 #"modulefinder", 168 #"multiprocessing", 169 #"netrc", 170 #"nntplib", 171 #"nturl2path", 172 #"numbers", 173 #"opcode", 174 #"optparse", 175 #"os2emxpath", 176 #"pdb", 177 #"pickle", 178 #"pickletools", 179 #"pipes", 180 #"pkgutil", 181 #"platform", 182 #"plat-linux2", 183 #"plistlib", 184 #"poplib", 185 #"pprint", 186 #"profile", 187 #"pstats", 188 #"pty", 189 #"pyclbr", 190 #"py_compile", 191 #"pydoc_data", 192 #"pydoc", 193 #"_pyio", 194 #"queue", 195 #"quopri", 196 "reprlib", 197 "rlcompleter", 198 #"runpy", 199 #"sched", 200 #"shelve", 201 #"shlex", 202 #"smtpd", 203 #"smtplib", 204 #"sndhdr", 205 #"socket", 206 #"socketserver", 207 #"sqlite3", 208 #"ssl", 209 #"stringprep", 210 #"string", 211 #"_strptime", 212 #"subprocess", 213 #"sunau", 214 #"symbol", 215 #"symtable", 216 #"sysconfig", 217 #"tabnanny", 218 #"telnetlib", 219 #"test", 220 #"textwrap", 221 #"this", 222 #"_threading_local", 223 #"threading", 224 #"timeit", 225 #"tkinter", 226 #"tokenize", 227 #"token", 228 #"traceback", 229 #"trace", 230 #"tty", 231 #"turtledemo", 232 #"turtle", 233 #"unittest", 234 #"urllib", 235 #"uuid", 236 #"uu", 237 #"wave", 238 "weakref", 239 #"webbrowser", 240 #"wsgiref", 241 #"xdrlib", 242 #"xml", 243 #"xmlrpc", 244 #"zipfile", 245 ]) 246 247if is_pypy: 248 # these are needed to correctly display the exceptions that may happen 249 # during the bootstrap 250 REQUIRED_MODULES.extend(['traceback', 'linecache']) 251 252class Logger(object): 253 254 """ 255 Logging object for use in command-line script. Allows ranges of 256 levels, to avoid some redundancy of displayed information. 257 """ 258 259 DEBUG = logging.DEBUG 260 INFO = logging.INFO 261 NOTIFY = (logging.INFO+logging.WARN)/2 262 WARN = WARNING = logging.WARN 263 ERROR = logging.ERROR 264 FATAL = logging.FATAL 265 266 LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL] 267 268 def __init__(self, consumers): 269 self.consumers = consumers 270 self.indent = 0 271 self.in_progress = None 272 self.in_progress_hanging = False 273 274 def debug(self, msg, *args, **kw): 275 self.log(self.DEBUG, msg, *args, **kw) 276 def info(self, msg, *args, **kw): 277 self.log(self.INFO, msg, *args, **kw) 278 def notify(self, msg, *args, **kw): 279 self.log(self.NOTIFY, msg, *args, **kw) 280 def warn(self, msg, *args, **kw): 281 self.log(self.WARN, msg, *args, **kw) 282 def error(self, msg, *args, **kw): 283 self.log(self.WARN, msg, *args, **kw) 284 def fatal(self, msg, *args, **kw): 285 self.log(self.FATAL, msg, *args, **kw) 286 def log(self, level, msg, *args, **kw): 287 if args: 288 if kw: 289 raise TypeError( 290 "You may give positional or keyword arguments, not both") 291 args = args or kw 292 rendered = None 293 for consumer_level, consumer in self.consumers: 294 if self.level_matches(level, consumer_level): 295 if (self.in_progress_hanging 296 and consumer in (sys.stdout, sys.stderr)): 297 self.in_progress_hanging = False 298 sys.stdout.write('\n') 299 sys.stdout.flush() 300 if rendered is None: 301 if args: 302 rendered = msg % args 303 else: 304 rendered = msg 305 rendered = ' '*self.indent + rendered 306 if hasattr(consumer, 'write'): 307 consumer.write(rendered+'\n') 308 else: 309 consumer(rendered) 310 311 def start_progress(self, msg): 312 assert not self.in_progress, ( 313 "Tried to start_progress(%r) while in_progress %r" 314 % (msg, self.in_progress)) 315 if self.level_matches(self.NOTIFY, self._stdout_level()): 316 sys.stdout.write(msg) 317 sys.stdout.flush() 318 self.in_progress_hanging = True 319 else: 320 self.in_progress_hanging = False 321 self.in_progress = msg 322 323 def end_progress(self, msg='done.'): 324 assert self.in_progress, ( 325 "Tried to end_progress without start_progress") 326 if self.stdout_level_matches(self.NOTIFY): 327 if not self.in_progress_hanging: 328 # Some message has been printed out since start_progress 329 sys.stdout.write('...' + self.in_progress + msg + '\n') 330 sys.stdout.flush() 331 else: 332 sys.stdout.write(msg + '\n') 333 sys.stdout.flush() 334 self.in_progress = None 335 self.in_progress_hanging = False 336 337 def show_progress(self): 338 """If we are in a progress scope, and no log messages have been 339 shown, write out another '.'""" 340 if self.in_progress_hanging: 341 sys.stdout.write('.') 342 sys.stdout.flush() 343 344 def stdout_level_matches(self, level): 345 """Returns true if a message at this level will go to stdout""" 346 return self.level_matches(level, self._stdout_level()) 347 348 def _stdout_level(self): 349 """Returns the level that stdout runs at""" 350 for level, consumer in self.consumers: 351 if consumer is sys.stdout: 352 return level 353 return self.FATAL 354 355 def level_matches(self, level, consumer_level): 356 """ 357 >>> l = Logger([]) 358 >>> l.level_matches(3, 4) 359 False 360 >>> l.level_matches(3, 2) 361 True 362 >>> l.level_matches(slice(None, 3), 3) 363 False 364 >>> l.level_matches(slice(None, 3), 2) 365 True 366 >>> l.level_matches(slice(1, 3), 1) 367 True 368 >>> l.level_matches(slice(2, 3), 1) 369 False 370 """ 371 if isinstance(level, slice): 372 start, stop = level.start, level.stop 373 if start is not None and start > consumer_level: 374 return False 375 if stop is not None and stop <= consumer_level: 376 return False 377 return True 378 else: 379 return level >= consumer_level 380 381 #@classmethod 382 def level_for_integer(cls, level): 383 levels = cls.LEVELS 384 if level < 0: 385 return levels[0] 386 if level >= len(levels): 387 return levels[-1] 388 return levels[level] 389 390 level_for_integer = classmethod(level_for_integer) 391 392# create a silent logger just to prevent this from being undefined 393# will be overridden with requested verbosity main() is called. 394logger = Logger([(Logger.LEVELS[-1], sys.stdout)]) 395 396def mkdir(path): 397 if not os.path.exists(path): 398 logger.info('Creating %s', path) 399 os.makedirs(path) 400 else: 401 logger.info('Directory %s already exists', path) 402 403def copyfileordir(src, dest): 404 if os.path.isdir(src): 405 shutil.copytree(src, dest, True) 406 else: 407 shutil.copy2(src, dest) 408 409def copyfile(src, dest, symlink=True): 410 if not os.path.exists(src): 411 # Some bad symlink in the src 412 logger.warn('Cannot find file %s (bad symlink)', src) 413 return 414 if os.path.exists(dest): 415 logger.debug('File %s already exists', dest) 416 return 417 if not os.path.exists(os.path.dirname(dest)): 418 logger.info('Creating parent directories for %s' % os.path.dirname(dest)) 419 os.makedirs(os.path.dirname(dest)) 420 if not os.path.islink(src): 421 srcpath = os.path.abspath(src) 422 else: 423 srcpath = os.readlink(src) 424 if symlink and hasattr(os, 'symlink'): 425 logger.info('Symlinking %s', dest) 426 try: 427 os.symlink(srcpath, dest) 428 except (OSError, NotImplementedError): 429 logger.info('Symlinking failed, copying to %s', dest) 430 copyfileordir(src, dest) 431 else: 432 logger.info('Copying to %s', dest) 433 copyfileordir(src, dest) 434 435def writefile(dest, content, overwrite=True): 436 if not os.path.exists(dest): 437 logger.info('Writing %s', dest) 438 f = open(dest, 'wb') 439 f.write(content.encode('utf-8')) 440 f.close() 441 return 442 else: 443 f = open(dest, 'rb') 444 c = f.read() 445 f.close() 446 if c != content: 447 if not overwrite: 448 logger.notify('File %s exists with different content; not overwriting', dest) 449 return 450 logger.notify('Overwriting %s with new content', dest) 451 f = open(dest, 'wb') 452 f.write(content.encode('utf-8')) 453 f.close() 454 else: 455 logger.info('Content %s already in place', dest) 456 457def rmtree(dir): 458 if os.path.exists(dir): 459 logger.notify('Deleting tree %s', dir) 460 shutil.rmtree(dir) 461 else: 462 logger.info('Do not need to delete %s; already gone', dir) 463 464def make_exe(fn): 465 if hasattr(os, 'chmod'): 466 oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777 467 newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777 468 os.chmod(fn, newmode) 469 logger.info('Changed mode of %s to %s', fn, oct(newmode)) 470 471def _find_file(filename, dirs): 472 for dir in dirs: 473 if os.path.exists(join(dir, filename)): 474 return join(dir, filename) 475 return filename 476 477def _install_req(py_executable, unzip=False, distribute=False, 478 search_dirs=None, never_download=False): 479 480 if search_dirs is None: 481 search_dirs = file_search_dirs() 482 483 if not distribute: 484 setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3] 485 project_name = 'setuptools' 486 bootstrap_script = EZ_SETUP_PY 487 source = None 488 else: 489 setup_fn = None 490 source = 'distribute-0.6.24.tar.gz' 491 project_name = 'distribute' 492 bootstrap_script = DISTRIBUTE_SETUP_PY 493 494 if setup_fn is not None: 495 setup_fn = _find_file(setup_fn, search_dirs) 496 497 if source is not None: 498 source = _find_file(source, search_dirs) 499 500 if is_jython and os._name == 'nt': 501 # Jython's .bat sys.executable can't handle a command line 502 # argument with newlines 503 fd, ez_setup = tempfile.mkstemp('.py') 504 os.write(fd, bootstrap_script) 505 os.close(fd) 506 cmd = [py_executable, ez_setup] 507 else: 508 cmd = [py_executable, '-c', bootstrap_script] 509 if unzip: 510 cmd.append('--always-unzip') 511 env = {} 512 remove_from_env = [] 513 if logger.stdout_level_matches(logger.DEBUG): 514 cmd.append('-v') 515 516 old_chdir = os.getcwd() 517 if setup_fn is not None and os.path.exists(setup_fn): 518 logger.info('Using existing %s egg: %s' % (project_name, setup_fn)) 519 cmd.append(setup_fn) 520 if os.environ.get('PYTHONPATH'): 521 env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH'] 522 else: 523 env['PYTHONPATH'] = setup_fn 524 else: 525 # the source is found, let's chdir 526 if source is not None and os.path.exists(source): 527 logger.info('Using existing %s egg: %s' % (project_name, source)) 528 os.chdir(os.path.dirname(source)) 529 # in this case, we want to be sure that PYTHONPATH is unset (not 530 # just empty, really unset), else CPython tries to import the 531 # site.py that it's in virtualenv_support 532 remove_from_env.append('PYTHONPATH') 533 else: 534 if never_download: 535 logger.fatal("Can't find any local distributions of %s to install " 536 "and --never-download is set. Either re-run virtualenv " 537 "without the --never-download option, or place a %s " 538 "distribution (%s) in one of these " 539 "locations: %r" % (project_name, project_name, 540 setup_fn or source, 541 search_dirs)) 542 sys.exit(1) 543 544 logger.info('No %s egg found; downloading' % project_name) 545 cmd.extend(['--always-copy', '-U', project_name]) 546 logger.start_progress('Installing %s...' % project_name) 547 logger.indent += 2 548 cwd = None 549 if project_name == 'distribute': 550 env['DONT_PATCH_SETUPTOOLS'] = 'true' 551 552 def _filter_ez_setup(line): 553 return filter_ez_setup(line, project_name) 554 555 if not os.access(os.getcwd(), os.W_OK): 556 cwd = tempfile.mkdtemp() 557 if source is not None and os.path.exists(source): 558 # the current working dir is hostile, let's copy the 559 # tarball to a temp dir 560 target = os.path.join(cwd, os.path.split(source)[-1]) 561 shutil.copy(source, target) 562 try: 563 call_subprocess(cmd, show_stdout=False, 564 filter_stdout=_filter_ez_setup, 565 extra_env=env, 566 remove_from_env=remove_from_env, 567 cwd=cwd) 568 finally: 569 logger.indent -= 2 570 logger.end_progress() 571 if os.getcwd() != old_chdir: 572 os.chdir(old_chdir) 573 if is_jython and os._name == 'nt': 574 os.remove(ez_setup) 575 576def file_search_dirs(): 577 here = os.path.dirname(os.path.abspath(__file__)) 578 dirs = ['.', here, 579 join(here, 'virtualenv_support')] 580 if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv': 581 # Probably some boot script; just in case virtualenv is installed... 582 try: 583 import virtualenv 584 except ImportError: 585 pass 586 else: 587 dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support')) 588 return [d for d in dirs if os.path.isdir(d)] 589 590def install_setuptools(py_executable, unzip=False, 591 search_dirs=None, never_download=False): 592 _install_req(py_executable, unzip, 593 search_dirs=search_dirs, never_download=never_download) 594 595def install_distribute(py_executable, unzip=False, 596 search_dirs=None, never_download=False): 597 _install_req(py_executable, unzip, distribute=True, 598 search_dirs=search_dirs, never_download=never_download) 599 600_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I) 601def install_pip(py_executable, search_dirs=None, never_download=False): 602 if search_dirs is None: 603 search_dirs = file_search_dirs() 604 605 filenames = [] 606 for dir in search_dirs: 607 filenames.extend([join(dir, fn) for fn in os.listdir(dir) 608 if _pip_re.search(fn)]) 609 filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)] 610 filenames.sort() 611 filenames = [filename for basename, i, filename in filenames] 612 if not filenames: 613 filename = 'pip' 614 else: 615 filename = filenames[-1] 616 easy_install_script = 'easy_install' 617 if sys.platform == 'win32': 618 easy_install_script = 'easy_install-script.py' 619 cmd = [join(os.path.dirname(py_executable), easy_install_script), filename] 620 if sys.platform == 'win32': 621 cmd.insert(0, py_executable) 622 if filename == 'pip': 623 if never_download: 624 logger.fatal("Can't find any local distributions of pip to install " 625 "and --never-download is set. Either re-run virtualenv " 626 "without the --never-download option, or place a pip " 627 "source distribution (zip/tar.gz/tar.bz2) in one of these " 628 "locations: %r" % search_dirs) 629 sys.exit(1) 630 logger.info('Installing pip from network...') 631 else: 632 logger.info('Installing existing %s distribution: %s' % ( 633 os.path.basename(filename), filename)) 634 logger.start_progress('Installing pip...') 635 logger.indent += 2 636 def _filter_setup(line): 637 return filter_ez_setup(line, 'pip') 638 try: 639 call_subprocess(cmd, show_stdout=False, 640 filter_stdout=_filter_setup) 641 finally: 642 logger.indent -= 2 643 logger.end_progress() 644 645def filter_ez_setup(line, project_name='setuptools'): 646 if not line.strip(): 647 return Logger.DEBUG 648 if project_name == 'distribute': 649 for prefix in ('Extracting', 'Now working', 'Installing', 'Before', 650 'Scanning', 'Setuptools', 'Egg', 'Already', 651 'running', 'writing', 'reading', 'installing', 652 'creating', 'copying', 'byte-compiling', 'removing', 653 'Processing'): 654 if line.startswith(prefix): 655 return Logger.DEBUG 656 return Logger.DEBUG 657 for prefix in ['Reading ', 'Best match', 'Processing setuptools', 658 'Copying setuptools', 'Adding setuptools', 659 'Installing ', 'Installed ']: 660 if line.startswith(prefix): 661 return Logger.DEBUG 662 return Logger.INFO 663 664 665class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter): 666 """ 667 Custom help formatter for use in ConfigOptionParser that updates 668 the defaults before expanding them, allowing them to show up correctly 669 in the help listing 670 """ 671 def expand_default(self, option): 672 if self.parser is not None: 673 self.parser.update_defaults(self.parser.defaults) 674 return optparse.IndentedHelpFormatter.expand_default(self, option) 675 676 677class ConfigOptionParser(optparse.OptionParser): 678 """ 679 Custom option parser which updates its defaults by by checking the 680 configuration files and environmental variables 681 """ 682 def __init__(self, *args, **kwargs): 683 self.config = ConfigParser.RawConfigParser() 684 self.files = self.get_config_files() 685 self.config.read(self.files) 686 optparse.OptionParser.__init__(self, *args, **kwargs) 687 688 def get_config_files(self): 689 config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False) 690 if config_file and os.path.exists(config_file): 691 return [config_file] 692 return [default_config_file] 693 694 def update_defaults(self, defaults): 695 """ 696 Updates the given defaults with values from the config files and 697 the environ. Does a little special handling for certain types of 698 options (lists). 699 """ 700 # Then go and look for the other sources of configuration: 701 config = {} 702 # 1. config files 703 config.update(dict(self.get_config_section('virtualenv'))) 704 # 2. environmental variables 705 config.update(dict(self.get_environ_vars())) 706 # Then set the options with those values 707 for key, val in config.items(): 708 key = key.replace('_', '-') 709 if not key.startswith('--'): 710 key = '--%s' % key # only prefer long opts 711 option = self.get_option(key) 712 if option is not None: 713 # ignore empty values 714 if not val: 715 continue 716 # handle multiline configs 717 if option.action == 'append': 718 val = val.split() 719 else: 720 option.nargs = 1 721 if option.action in ('store_true', 'store_false', 'count'): 722 val = strtobool(val) 723 try: 724 val = option.convert_value(key, val) 725 except optparse.OptionValueError: 726 e = sys.exc_info()[1] 727 print("An error occured during configuration: %s" % e) 728 sys.exit(3) 729 defaults[option.dest] = val 730 return defaults 731 732 def get_config_section(self, name): 733 """ 734 Get a section of a configuration 735 """ 736 if self.config.has_section(name): 737 return self.config.items(name) 738 return [] 739 740 def get_environ_vars(self, prefix='VIRTUALENV_'): 741 """ 742 Returns a generator with all environmental vars with prefix VIRTUALENV 743 """ 744 for key, val in os.environ.items(): 745 if key.startswith(prefix): 746 yield (key.replace(prefix, '').lower(), val) 747 748 def get_default_values(self): 749 """ 750 Overridding to make updating the defaults after instantiation of 751 the option parser possible, update_defaults() does the dirty work. 752 """ 753 if not self.process_default_values: 754 # Old, pre-Optik 1.5 behaviour. 755 return optparse.Values(self.defaults) 756 757 defaults = self.update_defaults(self.defaults.copy()) # ours 758 for option in self._get_all_options(): 759 default = defaults.get(option.dest) 760 if isinstance(default, basestring): 761 opt_str = option.get_opt_string() 762 defaults[option.dest] = option.check_value(opt_str, default) 763 return optparse.Values(defaults) 764 765 766def main(): 767 parser = ConfigOptionParser( 768 version=virtualenv_version, 769 usage="%prog [OPTIONS] DEST_DIR", 770 formatter=UpdatingDefaultsHelpFormatter()) 771 772 parser.add_option( 773 '-v', '--verbose', 774 action='count', 775 dest='verbose', 776 default=0, 777 help="Increase verbosity") 778 779 parser.add_option( 780 '-q', '--quiet', 781 action='count', 782 dest='quiet', 783 default=0, 784 help='Decrease verbosity') 785 786 parser.add_option( 787 '-p', '--python', 788 dest='python', 789 metavar='PYTHON_EXE', 790 help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 ' 791 'interpreter to create the new environment. The default is the interpreter that ' 792 'virtualenv was installed with (%s)' % sys.executable) 793 794 parser.add_option( 795 '--clear', 796 dest='clear', 797 action='store_true', 798 help="Clear out the non-root install and start from scratch") 799 800 parser.add_option( 801 '--no-site-packages', 802 dest='no_site_packages', 803 action='store_true', 804 help="Don't give access to the global site-packages dir to the " 805 "virtual environment") 806 807 parser.add_option( 808 '--system-site-packages', 809 dest='system_site_packages', 810 action='store_true', 811 help="Give access to the global site-packages dir to the " 812 "virtual environment") 813 814 parser.add_option( 815 '--unzip-setuptools', 816 dest='unzip_setuptools', 817 action='store_true', 818 help="Unzip Setuptools or Distribute when installing it") 819 820 parser.add_option( 821 '--relocatable', 822 dest='relocatable', 823 action='store_true', 824 help='Make an EXISTING virtualenv environment relocatable. ' 825 'This fixes up scripts and makes all .pth files relative') 826 827 parser.add_option( 828 '--distribute', 829 dest='use_distribute', 830 action='store_true', 831 help='Use Distribute instead of Setuptools. Set environ variable ' 832 'VIRTUALENV_DISTRIBUTE to make it the default ') 833 834 default_search_dirs = file_search_dirs() 835 parser.add_option( 836 '--extra-search-dir', 837 dest="search_dirs", 838 action="append", 839 default=default_search_dirs, 840 help="Directory to look for setuptools/distribute/pip distributions in. " 841 "You can add any number of additional --extra-search-dir paths.") 842 843 parser.add_option( 844 '--never-download', 845 dest="never_download", 846 action="store_true", 847 help="Never download anything from the network. Instead, virtualenv will fail " 848 "if local distributions of setuptools/distribute/pip are not present.") 849 850 parser.add_option( 851 '--prompt=', 852 dest='prompt', 853 help='Provides an alternative prompt prefix for this environment') 854 855 if 'extend_parser' in globals(): 856 extend_parser(parser) 857 858 options, args = parser.parse_args() 859 860 global logger 861 862 if 'adjust_options' in globals(): 863 adjust_options(options, args) 864 865 verbosity = options.verbose - options.quiet 866 logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)]) 867 868 if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): 869 env = os.environ.copy() 870 interpreter = resolve_interpreter(options.python) 871 if interpreter == sys.executable: 872 logger.warn('Already using interpreter %s' % interpreter) 873 else: 874 logger.notify('Running virtualenv with interpreter %s' % interpreter) 875 env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true' 876 file = __file__ 877 if file.endswith('.pyc'): 878 file = file[:-1] 879 popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env) 880 raise SystemExit(popen.wait()) 881 882 # Force --use-distribute on Python 3, since setuptools is not available. 883 if majver > 2: 884 options.use_distribute = True 885 886 if os.environ.get('PYTHONDONTWRITEBYTECODE') and not options.use_distribute: 887 print( 888 "The PYTHONDONTWRITEBYTECODE environment variable is " 889 "not compatible with setuptools. Either use --distribute " 890 "or unset PYTHONDONTWRITEBYTECODE.") 891 sys.exit(2) 892 if not args: 893 print('You must provide a DEST_DIR') 894 parser.print_help() 895 sys.exit(2) 896 if len(args) > 1: 897 print('There must be only one argument: DEST_DIR (you gave %s)' % ( 898 ' '.join(args))) 899 parser.print_help() 900 sys.exit(2) 901 902 home_dir = args[0] 903 904 if os.environ.get('WORKING_ENV'): 905 logger.fatal('ERROR: you cannot run virtualenv while in a workingenv') 906 logger.fatal('Please deactivate your workingenv, then re-run this script') 907 sys.exit(3) 908 909 if 'PYTHONHOME' in os.environ: 910 logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it') 911 del os.environ['PYTHONHOME'] 912 913 if options.relocatable: 914 make_environment_relocatable(home_dir) 915 return 916 917 if options.no_site_packages: 918 logger.warn('The --no-site-packages flag is deprecated; it is now ' 919 'the default behavior.') 920 921 create_environment(home_dir, 922 site_packages=options.system_site_packages, 923 clear=options.clear, 924 unzip_setuptools=options.unzip_setuptools, 925 use_distribute=options.use_distribute, 926 prompt=options.prompt, 927 search_dirs=options.search_dirs, 928 never_download=options.never_download) 929 if 'after_install' in globals(): 930 after_install(options, home_dir) 931 932def call_subprocess(cmd, show_stdout=True, 933 filter_stdout=None, cwd=None, 934 raise_on_returncode=True, extra_env=None, 935 remove_from_env=None): 936 cmd_parts = [] 937 for part in cmd: 938 if len(part) > 45: 939 part = part[:20]+"..."+part[-20:] 940 if ' ' in part or '\n' in part or '"' in part or "'" in part: 941 part = '"%s"' % part.replace('"', '\\"') 942 if hasattr(part, 'decode'): 943 try: 944 part = part.decode(sys.getdefaultencoding()) 945 except UnicodeDecodeError: 946 part = part.decode(sys.getfilesystemencoding()) 947 cmd_parts.append(part) 948 cmd_desc = ' '.join(cmd_parts) 949 if show_stdout: 950 stdout = None 951 else: 952 stdout = subprocess.PIPE 953 logger.debug("Running command %s" % cmd_desc) 954 if extra_env or remove_from_env: 955 env = os.environ.copy() 956 if extra_env: 957 env.update(extra_env) 958 if remove_from_env: 959 for varname in remove_from_env: 960 env.pop(varname, None) 961 else: 962 env = None 963 try: 964 proc = subprocess.Popen( 965 cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout, 966 cwd=cwd, env=env) 967 except Exception: 968 e = sys.exc_info()[1] 969 logger.fatal( 970 "Error %s while executing command %s" % (e, cmd_desc)) 971 raise 972 all_output = [] 973 if stdout is not None: 974 stdout = proc.stdout 975 encoding = sys.getdefaultencoding() 976 fs_encoding = sys.getfilesystemencoding() 977 while 1: 978 line = stdout.readline() 979 try: 980 line = line.decode(encoding) 981 except UnicodeDecodeError: 982 line = line.decode(fs_encoding) 983 if not line: 984 break 985 line = line.rstrip() 986 all_output.append(line) 987 if filter_stdout: 988 level = filter_stdout(line) 989 if isinstance(level, tuple): 990 level, line = level 991 logger.log(level, line) 992 if not logger.stdout_level_matches(level): 993 logger.show_progress() 994 else: 995 logger.info(line) 996 else: 997 proc.communicate() 998 proc.wait() 999 if proc.returncode: 1000 if raise_on_returncode: 1001 if all_output: 1002 logger.notify('Complete output from command %s:' % cmd_desc) 1003 logger.notify('\n'.join(all_output) + '\n----------------------------------------') 1004 raise OSError( 1005 "Command %s failed with error code %s" 1006 % (cmd_desc, proc.returncode)) 1007 else: 1008 logger.warn( 1009 "Command %s had error code %s" 1010 % (cmd_desc, proc.returncode)) 1011 1012 1013def create_environment(home_dir, site_packages=False, clear=False, 1014 unzip_setuptools=False, use_distribute=False, 1015 prompt=None, search_dirs=None, never_download=False): 1016 """ 1017 Creates a new environment in ``home_dir``. 1018 1019 If ``site_packages`` is true, then the global ``site-packages/`` 1020 directory will be on the path. 1021 1022 If ``clear`` is true (default False) then the environment will 1023 first be cleared. 1024 """ 1025 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1026 1027 py_executable = os.path.abspath(install_python( 1028 home_dir, lib_dir, inc_dir, bin_dir, 1029 site_packages=site_packages, clear=clear)) 1030 1031 install_distutils(home_dir) 1032 1033 # use_distribute also is True if VIRTUALENV_DISTRIBUTE env var is set 1034 # we also check VIRTUALENV_USE_DISTRIBUTE for backwards compatibility 1035 if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'): 1036 install_distribute(py_executable, unzip=unzip_setuptools, 1037 search_dirs=search_dirs, never_download=never_download) 1038 else: 1039 install_setuptools(py_executable, unzip=unzip_setuptools, 1040 search_dirs=search_dirs, never_download=never_download) 1041 1042 install_pip(py_executable, search_dirs=search_dirs, never_download=never_download) 1043 1044 install_activate(home_dir, bin_dir, prompt) 1045 1046def path_locations(home_dir): 1047 """Return the path locations for the environment (where libraries are, 1048 where scripts go, etc)""" 1049 # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its 1050 # prefix arg is broken: http://bugs.python.org/issue3386 1051 if sys.platform == 'win32': 1052 # Windows has lots of problems with executables with spaces in 1053 # the name; this function will remove them (using the ~1 1054 # format): 1055 mkdir(home_dir) 1056 if ' ' in home_dir: 1057 try: 1058 import win32api 1059 except ImportError: 1060 print('Error: the path "%s" has a space in it' % home_dir) 1061 print('To handle these kinds of paths, the win32api module must be installed:') 1062 print(' http://sourceforge.net/projects/pywin32/') 1063 sys.exit(3) 1064 home_dir = win32api.GetShortPathName(home_dir) 1065 lib_dir = join(home_dir, 'Lib') 1066 inc_dir = join(home_dir, 'Include') 1067 bin_dir = join(home_dir, 'Scripts') 1068 elif is_jython: 1069 lib_dir = join(home_dir, 'Lib') 1070 inc_dir = join(home_dir, 'Include') 1071 bin_dir = join(home_dir, 'bin') 1072 elif is_pypy: 1073 lib_dir = home_dir 1074 inc_dir = join(home_dir, 'include') 1075 bin_dir = join(home_dir, 'bin') 1076 else: 1077 lib_dir = join(home_dir, 'lib', py_version) 1078 inc_dir = join(home_dir, 'include', py_version + abiflags) 1079 bin_dir = join(home_dir, 'bin') 1080 return home_dir, lib_dir, inc_dir, bin_dir 1081 1082 1083def change_prefix(filename, dst_prefix): 1084 prefixes = [sys.prefix] 1085 1086 if sys.platform == "darwin": 1087 prefixes.extend(( 1088 os.path.join("/Library/Python", sys.version[:3], "site-packages"), 1089 os.path.join(sys.prefix, "Extras", "lib", "python"), 1090 os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"))) 1091 1092 if hasattr(sys, 'real_prefix'): 1093 prefixes.append(sys.real_prefix) 1094 prefixes = list(map(os.path.abspath, prefixes)) 1095 filename = os.path.abspath(filename) 1096 for src_prefix in prefixes: 1097 if filename.startswith(src_prefix): 1098 _, relpath = filename.split(src_prefix, 1) 1099 assert relpath[0] == os.sep 1100 relpath = relpath[1:] 1101 return join(dst_prefix, relpath) 1102 assert False, "Filename %s does not start with any of these prefixes: %s" % \ 1103 (filename, prefixes) 1104 1105def copy_required_modules(dst_prefix): 1106 import imp 1107 for modname in REQUIRED_MODULES: 1108 if modname in sys.builtin_module_names: 1109 logger.info("Ignoring built-in bootstrap module: %s" % modname) 1110 continue 1111 try: 1112 f, filename, _ = imp.find_module(modname) 1113 except ImportError: 1114 logger.info("Cannot import bootstrap module: %s" % modname) 1115 else: 1116 if f is not None: 1117 f.close() 1118 dst_filename = change_prefix(filename, dst_prefix) 1119 copyfile(filename, dst_filename) 1120 if filename.endswith('.pyc'): 1121 pyfile = filename[:-1] 1122 if os.path.exists(pyfile): 1123 copyfile(pyfile, dst_filename[:-1]) 1124 1125 1126def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear): 1127 """Install just the base environment, no distutils patches etc""" 1128 if sys.executable.startswith(bin_dir): 1129 print('Please use the *system* python to run this script') 1130 return 1131 1132 if clear: 1133 rmtree(lib_dir) 1134 ## FIXME: why not delete it? 1135 ## Maybe it should delete everything with #!/path/to/venv/python in it 1136 logger.notify('Not deleting %s', bin_dir) 1137 1138 if hasattr(sys, 'real_prefix'): 1139 logger.notify('Using real prefix %r' % sys.real_prefix) 1140 prefix = sys.real_prefix 1141 else: 1142 prefix = sys.prefix 1143 mkdir(lib_dir) 1144 fix_lib64(lib_dir) 1145 fix_local_scheme(home_dir) 1146 stdlib_dirs = [os.path.dirname(os.__file__)] 1147 if sys.platform == 'win32': 1148 stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs')) 1149 elif sys.platform == 'darwin': 1150 stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages')) 1151 if hasattr(os, 'symlink'): 1152 logger.info('Symlinking Python bootstrap modules') 1153 else: 1154 logger.info('Copying Python bootstrap modules') 1155 logger.indent += 2 1156 try: 1157 # copy required files... 1158 for stdlib_dir in stdlib_dirs: 1159 if not os.path.isdir(stdlib_dir): 1160 continue 1161 for fn in os.listdir(stdlib_dir): 1162 bn = os.path.splitext(fn)[0] 1163 if fn != 'site-packages' and bn in REQUIRED_FILES: 1164 copyfile(join(stdlib_dir, fn), join(lib_dir, fn)) 1165 # ...and modules 1166 copy_required_modules(home_dir) 1167 finally: 1168 logger.indent -= 2 1169 mkdir(join(lib_dir, 'site-packages')) 1170 import site 1171 site_filename = site.__file__ 1172 if site_filename.endswith('.pyc'): 1173 site_filename = site_filename[:-1] 1174 elif site_filename.endswith('$py.class'): 1175 site_filename = site_filename.replace('$py.class', '.py') 1176 site_filename_dst = change_prefix(site_filename, home_dir) 1177 site_dir = os.path.dirname(site_filename_dst) 1178 writefile(site_filename_dst, SITE_PY) 1179 writefile(join(site_dir, 'orig-prefix.txt'), prefix) 1180 site_packages_filename = join(site_dir, 'no-global-site-packages.txt') 1181 if not site_packages: 1182 writefile(site_packages_filename, '') 1183 else: 1184 if os.path.exists(site_packages_filename): 1185 logger.info('Deleting %s' % site_packages_filename) 1186 os.unlink(site_packages_filename) 1187 1188 if is_pypy or is_win: 1189 stdinc_dir = join(prefix, 'include') 1190 else: 1191 stdinc_dir = join(prefix, 'include', py_version + abiflags) 1192 if os.path.exists(stdinc_dir): 1193 copyfile(stdinc_dir, inc_dir) 1194 else: 1195 logger.debug('No include dir %s' % stdinc_dir) 1196 1197 # pypy never uses exec_prefix, just ignore it 1198 if sys.exec_prefix != prefix and not is_pypy: 1199 if sys.platform == 'win32': 1200 exec_dir = join(sys.exec_prefix, 'lib') 1201 elif is_jython: 1202 exec_dir = join(sys.exec_prefix, 'Lib') 1203 else: 1204 exec_dir = join(sys.exec_prefix, 'lib', py_version) 1205 for fn in os.listdir(exec_dir): 1206 copyfile(join(exec_dir, fn), join(lib_dir, fn)) 1207 1208 if is_jython: 1209 # Jython has either jython-dev.jar and javalib/ dir, or just 1210 # jython.jar 1211 for name in 'jython-dev.jar', 'javalib', 'jython.jar': 1212 src = join(prefix, name) 1213 if os.path.exists(src): 1214 copyfile(src, join(home_dir, name)) 1215 # XXX: registry should always exist after Jython 2.5rc1 1216 src = join(prefix, 'registry') 1217 if os.path.exists(src): 1218 copyfile(src, join(home_dir, 'registry'), symlink=False) 1219 copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'), 1220 symlink=False) 1221 1222 mkdir(bin_dir) 1223 py_executable = join(bin_dir, os.path.basename(sys.executable)) 1224 if 'Python.framework' in prefix: 1225 if re.search(r'/Python(?:-32|-64)*$', py_executable): 1226 # The name of the python executable is not quite what 1227 # we want, rename it. 1228 py_executable = os.path.join( 1229 os.path.dirname(py_executable), 'python') 1230 1231 logger.notify('New %s executable in %s', expected_exe, py_executable) 1232 if sys.executable != py_executable: 1233 ## FIXME: could I just hard link? 1234 executable = sys.executable 1235 if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'): 1236 # Cygwin misreports sys.executable sometimes 1237 executable += '.exe' 1238 py_executable += '.exe' 1239 logger.info('Executable actually exists in %s' % executable) 1240 shutil.copyfile(executable, py_executable) 1241 make_exe(py_executable) 1242 if sys.platform == 'win32' or sys.platform == 'cygwin': 1243 pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe') 1244 if os.path.exists(pythonw): 1245 logger.info('Also created pythonw.exe') 1246 shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe')) 1247 if is_pypy: 1248 # make a symlink python --> pypy-c 1249 python_executable = os.path.join(os.path.dirname(py_executable), 'python') 1250 logger.info('Also created executable %s' % python_executable) 1251 copyfile(py_executable, python_executable) 1252 1253 if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe: 1254 secondary_exe = os.path.join(os.path.dirname(py_executable), 1255 expected_exe) 1256 py_executable_ext = os.path.splitext(py_executable)[1] 1257 if py_executable_ext == '.exe': 1258 # python2.4 gives an extension of '.4' :P 1259 secondary_exe += py_executable_ext 1260 if os.path.exists(secondary_exe): 1261 logger.warn('Not overwriting existing %s script %s (you must use %s)' 1262 % (expected_exe, secondary_exe, py_executable)) 1263 else: 1264 logger.notify('Also creating executable in %s' % secondary_exe) 1265 shutil.copyfile(sys.executable, secondary_exe) 1266 make_exe(secondary_exe) 1267 1268 if 'Python.framework' in prefix: 1269 logger.debug('MacOSX Python framework detected') 1270 1271 # Make sure we use the the embedded interpreter inside 1272 # the framework, even if sys.executable points to 1273 # the stub executable in ${sys.prefix}/bin 1274 # See http://groups.google.com/group/python-virtualenv/ 1275 # browse_thread/thread/17cab2f85da75951 1276 original_python = os.path.join( 1277 prefix, 'Resources/Python.app/Contents/MacOS/Python') 1278 shutil.copy(original_python, py_executable) 1279 1280 # Copy the framework's dylib into the virtual 1281 # environment 1282 virtual_lib = os.path.join(home_dir, '.Python') 1283 1284 if os.path.exists(virtual_lib): 1285 os.unlink(virtual_lib) 1286 copyfile( 1287 os.path.join(prefix, 'Python'), 1288 virtual_lib) 1289 1290 # And then change the install_name of the copied python executable 1291 try: 1292 call_subprocess( 1293 ["install_name_tool", "-change", 1294 os.path.join(prefix, 'Python'), 1295 '@executable_path/../.Python', 1296 py_executable]) 1297 except: 1298 logger.fatal( 1299 "Could not call install_name_tool -- you must have Apple's development tools installed") 1300 raise 1301 1302 # Some tools depend on pythonX.Y being present 1303 py_executable_version = '%s.%s' % ( 1304 sys.version_info[0], sys.version_info[1]) 1305 if not py_executable.endswith(py_executable_version): 1306 # symlinking pythonX.Y > python 1307 pth = py_executable + '%s.%s' % ( 1308 sys.version_info[0], sys.version_info[1]) 1309 if os.path.exists(pth): 1310 os.unlink(pth) 1311 os.symlink('python', pth) 1312 else: 1313 # reverse symlinking python -> pythonX.Y (with --python) 1314 pth = join(bin_dir, 'python') 1315 if os.path.exists(pth): 1316 os.unlink(pth) 1317 os.symlink(os.path.basename(py_executable), pth) 1318 1319 if sys.platform == 'win32' and ' ' in py_executable: 1320 # There's a bug with subprocess on Windows when using a first 1321 # argument that has a space in it. Instead we have to quote 1322 # the value: 1323 py_executable = '"%s"' % py_executable 1324 cmd = [py_executable, '-c', """ 1325import sys 1326prefix = sys.prefix 1327if sys.version_info[0] == 3: 1328 prefix = prefix.encode('utf8') 1329if hasattr(sys.stdout, 'detach'): 1330 sys.stdout = sys.stdout.detach() 1331elif hasattr(sys.stdout, 'buffer'): 1332 sys.stdout = sys.stdout.buffer 1333sys.stdout.write(prefix) 1334"""] 1335 logger.info('Testing executable with %s %s "%s"' % tuple(cmd)) 1336 try: 1337 proc = subprocess.Popen(cmd, 1338 stdout=subprocess.PIPE) 1339 proc_stdout, proc_stderr = proc.communicate() 1340 except OSError: 1341 e = sys.exc_info()[1] 1342 if e.errno == errno.EACCES: 1343 logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e)) 1344 sys.exit(100) 1345 else: 1346 raise e 1347 1348 proc_stdout = proc_stdout.strip().decode("utf-8") 1349 proc_stdout = os.path.normcase(os.path.abspath(proc_stdout)) 1350 norm_home_dir = os.path.normcase(os.path.abspath(home_dir)) 1351 if hasattr(norm_home_dir, 'decode'): 1352 norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding()) 1353 if proc_stdout != norm_home_dir: 1354 logger.fatal( 1355 'ERROR: The executable %s is not functioning' % py_executable) 1356 logger.fatal( 1357 'ERROR: It thinks sys.prefix is %r (should be %r)' 1358 % (proc_stdout, norm_home_dir)) 1359 logger.fatal( 1360 'ERROR: virtualenv is not compatible with this system or executable') 1361 if sys.platform == 'win32': 1362 logger.fatal( 1363 'Note: some Windows users have reported this error when they installed Python for "Only this user". The problem may be resolvable if you install Python "For all users". (See https://bugs.launchpad.net/virtualenv/+bug/352844)') 1364 sys.exit(100) 1365 else: 1366 logger.info('Got sys.prefix result: %r' % proc_stdout) 1367 1368 pydistutils = os.path.expanduser('~/.pydistutils.cfg') 1369 if os.path.exists(pydistutils): 1370 logger.notify('Please make sure you remove any previous custom paths from ' 1371 'your %s file.' % pydistutils) 1372 ## FIXME: really this should be calculated earlier 1373 return py_executable 1374 1375def install_activate(home_dir, bin_dir, prompt=None): 1376 if sys.platform == 'win32' or is_jython and os._name == 'nt': 1377 files = {'activate.bat': ACTIVATE_BAT, 1378 'deactivate.bat': DEACTIVATE_BAT} 1379 if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin': 1380 files['activate'] = ACTIVATE_SH 1381 else: 1382 files = {'activate': ACTIVATE_SH} 1383 1384 # suppling activate.fish in addition to, not instead of, the 1385 # bash script support. 1386 files['activate.fish'] = ACTIVATE_FISH 1387 1388 # same for csh/tcsh support... 1389 files['activate.csh'] = ACTIVATE_CSH 1390 1391 1392 1393 files['activate_this.py'] = ACTIVATE_THIS 1394 home_dir = os.path.abspath(home_dir) 1395 if hasattr(home_dir, 'decode'): 1396 home_dir = home_dir.decode(sys.getfilesystemencoding()) 1397 vname = os.path.basename(home_dir) 1398 for name, content in files.items(): 1399 content = content.replace('__VIRTUAL_PROMPT__', prompt or '') 1400 content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname) 1401 content = content.replace('__VIRTUAL_ENV__', home_dir) 1402 content = content.replace('__VIRTUAL_NAME__', vname) 1403 content = content.replace('__BIN_NAME__', os.path.basename(bin_dir)) 1404 writefile(os.path.join(bin_dir, name), content) 1405 1406def install_distutils(home_dir): 1407 distutils_path = change_prefix(distutils.__path__[0], home_dir) 1408 mkdir(distutils_path) 1409 ## FIXME: maybe this prefix setting should only be put in place if 1410 ## there's a local distutils.cfg with a prefix setting? 1411 home_dir = os.path.abspath(home_dir) 1412 ## FIXME: this is breaking things, removing for now: 1413 #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir 1414 writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT) 1415 writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False) 1416 1417def fix_local_scheme(home_dir): 1418 """ 1419 Platforms that use the "posix_local" install scheme (like Ubuntu with 1420 Python 2.7) need to be given an additional "local" location, sigh. 1421 """ 1422 try: 1423 import sysconfig 1424 except ImportError: 1425 pass 1426 else: 1427 if sysconfig._get_default_scheme() == 'posix_local': 1428 local_path = os.path.join(home_dir, 'local') 1429 if not os.path.exists(local_path): 1430 os.symlink(os.path.abspath(home_dir), local_path) 1431 1432def fix_lib64(lib_dir): 1433 """ 1434 Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y 1435 instead of lib/pythonX.Y. If this is such a platform we'll just create a 1436 symlink so lib64 points to lib 1437 """ 1438 if [p for p in distutils.sysconfig.get_config_vars().values() 1439 if isinstance(p, basestring) and 'lib64' in p]: 1440 logger.debug('This system uses lib64; symlinking lib64 to lib') 1441 assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], ( 1442 "Unexpected python lib dir: %r" % lib_dir) 1443 lib_parent = os.path.dirname(lib_dir) 1444 assert os.path.basename(lib_parent) == 'lib', ( 1445 "Unexpected parent dir: %r" % lib_parent) 1446 copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64')) 1447 1448def resolve_interpreter(exe): 1449 """ 1450 If the executable given isn't an absolute path, search $PATH for the interpreter 1451 """ 1452 if os.path.abspath(exe) != exe: 1453 paths = os.environ.get('PATH', '').split(os.pathsep) 1454 for path in paths: 1455 if os.path.exists(os.path.join(path, exe)): 1456 exe = os.path.join(path, exe) 1457 break 1458 if not os.path.exists(exe): 1459 logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe)) 1460 raise SystemExit(3) 1461 if not is_executable(exe): 1462 logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe)) 1463 raise SystemExit(3) 1464 return exe 1465 1466def is_executable(exe): 1467 """Checks a file is executable""" 1468 return os.access(exe, os.X_OK) 1469 1470############################################################ 1471## Relocating the environment: 1472 1473def make_environment_relocatable(home_dir): 1474 """ 1475 Makes the already-existing environment use relative paths, and takes out 1476 the #!-based environment selection in scripts. 1477 """ 1478 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1479 activate_this = os.path.join(bin_dir, 'activate_this.py') 1480 if not os.path.exists(activate_this): 1481 logger.fatal( 1482 'The environment doesn\'t have a file %s -- please re-run virtualenv ' 1483 'on this environment to update it' % activate_this) 1484 fixup_scripts(home_dir) 1485 fixup_pth_and_egg_link(home_dir) 1486 ## FIXME: need to fix up distutils.cfg 1487 1488OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3], 1489 'activate', 'activate.bat', 'activate_this.py'] 1490 1491def fixup_scripts(home_dir): 1492 # This is what we expect at the top of scripts: 1493 shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir)) 1494 # This is what we'll put: 1495 new_shebang = '#!/usr/bin/env python%s' % sys.version[:3] 1496 activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this" 1497 if sys.platform == 'win32': 1498 bin_suffix = 'Scripts' 1499 else: 1500 bin_suffix = 'bin' 1501 bin_dir = os.path.join(home_dir, bin_suffix) 1502 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1503 for filename in os.listdir(bin_dir): 1504 filename = os.path.join(bin_dir, filename) 1505 if not os.path.isfile(filename): 1506 # ignore subdirs, e.g. .svn ones. 1507 continue 1508 f = open(filename, 'rb') 1509 lines = f.readlines() 1510 f.close() 1511 if not lines: 1512 logger.warn('Script %s is an empty file' % filename) 1513 continue 1514 if not lines[0].strip().startswith(shebang): 1515 if os.path.basename(filename) in OK_ABS_SCRIPTS: 1516 logger.debug('Cannot make script %s relative' % filename) 1517 elif lines[0].strip() == new_shebang: 1518 logger.info('Script %s has already been made relative' % filename) 1519 else: 1520 logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)' 1521 % (filename, shebang)) 1522 continue 1523 logger.notify('Making script %s relative' % filename) 1524 lines = [new_shebang+'\n', activate+'\n'] + lines[1:] 1525 f = open(filename, 'wb') 1526 f.writelines(lines) 1527 f.close() 1528 1529def fixup_pth_and_egg_link(home_dir, sys_path=None): 1530 """Makes .pth and .egg-link files use relative paths""" 1531 home_dir = os.path.normcase(os.path.abspath(home_dir)) 1532 if sys_path is None: 1533 sys_path = sys.path 1534 for path in sys_path: 1535 if not path: 1536 path = '.' 1537 if not os.path.isdir(path): 1538 continue 1539 path = os.path.normcase(os.path.abspath(path)) 1540 if not path.startswith(home_dir): 1541 logger.debug('Skipping system (non-environment) directory %s' % path) 1542 continue 1543 for filename in os.listdir(path): 1544 filename = os.path.join(path, filename) 1545 if filename.endswith('.pth'): 1546 if not os.access(filename, os.W_OK): 1547 logger.warn('Cannot write .pth file %s, skipping' % filename) 1548 else: 1549 fixup_pth_file(filename) 1550 if filename.endswith('.egg-link'): 1551 if not os.access(filename, os.W_OK): 1552 logger.warn('Cannot write .egg-link file %s, skipping' % filename) 1553 else: 1554 fixup_egg_link(filename) 1555 1556def fixup_pth_file(filename): 1557 lines = [] 1558 prev_lines = [] 1559 f = open(filename) 1560 prev_lines = f.readlines() 1561 f.close() 1562 for line in prev_lines: 1563 line = line.strip() 1564 if (not line or line.startswith('#') or line.startswith('import ') 1565 or os.path.abspath(line) != line): 1566 lines.append(line) 1567 else: 1568 new_value = make_relative_path(filename, line) 1569 if line != new_value: 1570 logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename)) 1571 lines.append(new_value) 1572 if lines == prev_lines: 1573 logger.info('No changes to .pth file %s' % filename) 1574 return 1575 logger.notify('Making paths in .pth file %s relative' % filename) 1576 f = open(filename, 'w') 1577 f.write('\n'.join(lines) + '\n') 1578 f.close() 1579 1580def fixup_egg_link(filename): 1581 f = open(filename) 1582 link = f.read().strip() 1583 f.close() 1584 if os.path.abspath(link) != link: 1585 logger.debug('Link in %s already relative' % filename) 1586 return 1587 new_link = make_relative_path(filename, link) 1588 logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link)) 1589 f = open(filename, 'w') 1590 f.write(new_link) 1591 f.close() 1592 1593def make_relative_path(source, dest, dest_is_directory=True): 1594 """ 1595 Make a filename relative, where the filename is dest, and it is 1596 being referred to from the filename source. 1597 1598 >>> make_relative_path('/usr/share/something/a-file.pth', 1599 ... '/usr/share/another-place/src/Directory') 1600 '../another-place/src/Directory' 1601 >>> make_relative_path('/usr/share/something/a-file.pth', 1602 ... '/home/user/src/Directory') 1603 '../../../home/user/src/Directory' 1604 >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/') 1605 './' 1606 """ 1607 source = os.path.dirname(source) 1608 if not dest_is_directory: 1609 dest_filename = os.path.basename(dest) 1610 dest = os.path.dirname(dest) 1611 dest = os.path.normpath(os.path.abspath(dest)) 1612 source = os.path.normpath(os.path.abspath(source)) 1613 dest_parts = dest.strip(os.path.sep).split(os.path.sep) 1614 source_parts = source.strip(os.path.sep).split(os.path.sep) 1615 while dest_parts and source_parts and dest_parts[0] == source_parts[0]: 1616 dest_parts.pop(0) 1617 source_parts.pop(0) 1618 full_parts = ['..']*len(source_parts) + dest_parts 1619 if not dest_is_directory: 1620 full_parts.append(dest_filename) 1621 if not full_parts: 1622 # Special case for the current directory (otherwise it'd be '') 1623 return './' 1624 return os.path.sep.join(full_parts) 1625 1626 1627 1628############################################################ 1629## Bootstrap script creation: 1630 1631def create_bootstrap_script(extra_text, python_version=''): 1632 """ 1633 Creates a bootstrap script, which is like this script but with 1634 extend_parser, adjust_options, and after_install hooks. 1635 1636 This returns a string that (written to disk of course) can be used 1637 as a bootstrap script with your own customizations. The script 1638 will be the standard virtualenv.py script, with your extra text 1639 added (your extra text should be Python code). 1640 1641 If you include these functions, they will be called: 1642 1643 ``extend_parser(optparse_parser)``: 1644 You can add or remove options from the parser here. 1645 1646 ``adjust_options(options, args)``: 1647 You can change options here, or change the args (if you accept 1648 different kinds of arguments, be sure you modify ``args`` so it is 1649 only ``[DEST_DIR]``). 1650 1651 ``after_install(options, home_dir)``: 1652 1653 After everything is installed, this function is called. This 1654 is probably the function you are most likely to use. An 1655 example would be:: 1656 1657 def after_install(options, home_dir): 1658 subprocess.call([join(home_dir, 'bin', 'easy_install'), 1659 'MyPackage']) 1660 subprocess.call([join(home_dir, 'bin', 'my-package-script'), 1661 'setup', home_dir]) 1662 1663 This example immediately installs a package, and runs a setup 1664 script from that package. 1665 1666 If you provide something like ``python_version='2.4'`` then the 1667 script will start with ``#!/usr/bin/env python2.4`` instead of 1668 ``#!/usr/bin/env python``. You can use this when the script must 1669 be run with a particular Python version. 1670 """ 1671 filename = __file__ 1672 if filename.endswith('.pyc'): 1673 filename = filename[:-1] 1674 f = open(filename, 'rb') 1675 content = f.read() 1676 f.close() 1677 py_exe = 'python%s' % python_version 1678 content = (('#!/usr/bin/env %s\n' % py_exe) 1679 + '## WARNING: This file is generated\n' 1680 + content) 1681 return content.replace('##EXT' 'END##', extra_text) 1682 1683##EXTEND## 1684 1685def convert(s): 1686 b = base64.b64decode(s.encode('ascii')) 1687 return zlib.decompress(b).decode('utf-8') 1688 1689##file site.py 1690SITE_PY = convert(""" 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 1766X4UuruF1rMoshUjuVWhlSXfDcoyWcfRDu6HKeA1pQKc7jKwb8qz3YoFW61XIc9P9xy2j/dYAhi2D 1767vYV555LKEahGF4upRIiNeOcglF/gq116vQYKFgw3lmpcRMN0Kcw+geBarFMIIIAn12B9MU4ACJ2V 17688BPQx052QBZYDRC+2SwO/xpqgvitf/lloHldZYd/FyVEQYJLV8IBYrqN30LgE8tYnH14Nw4ZOSoF 1769FX9tsIAcHBLK8jnSTvUyvGM7jZTMlrqewdcH+EL7CfS6072SZaW7D7vGIUrAExWR1/BEGfqFWF5k 1770YU9wKuMOaKyNt5jhGTN329t8DsTHtcwyXRF9/vbiDHxHLNdHCeJ9njMYjvMluGWri734DFwHFG7o 1771wusK2bhCF5Y29Rex12wwM4siR729OgC7TpT97PfqpTqrJFUu2hFOm2GZgvMYWRnWwiwrs3anDVLY 1772bUMUR5lhlpheVlQw6fME8DI9TTgkglgJDwOYNDPvWqZ5bSrksnQOehRULijUCQgJEhdPvBHnFTkn 1773eotKmYMy8LDcVelqXWMyHTrHVKSPzX88/Xxx/p4K11+8bL3uAeacUCQw4aKFEyxJw2wHfHHLzJCr 1774ptMhntWvEAZqH/jTfcXVECc8QK8fJxbxT/cVn1Q6cSJBngEoqKbsigcGAE63IblpZYFxtXEwftyS 1775sxYzHwzlIvFghC4scOfX50TbsmNKKO9jXj5il2JZahpGprNbAtX96DkuS9xWWUTDjeDtkGyZzwy6 17763vTe7Cu2cj89KcRDk4BRv7U/hqlG6jXV03GYbR+3UFirbewvuZMrddrNcxRlIGLkdh67TDashHVz 17775kCvbLcHTHyr0TWSOKjKR7/kI+1heJhYYvfiFNORjk2QEcBMhtSnQxrwodAigAKhatPIkdzJ+OkL 1778b46ONbh/jlp3gW38ARShrv2kMwVFBZwIX35jx5FfEVqoR49F6HgqucwLW5eEn+0avcrn/hwHZYCS 1779mCh2VZKvZMSwJgbmVz6x96RgSdt6pL5Kr4cMizgH5/TLHg7vy8XwxolBrcMIvXY3ctdVRz55sMHg 17800YM7CeaDr5It6P6yqSNeyWGRHz5ttR/q/RCx2g2a6s3eKMR0zG/hnvVpAQ9SQ8NCD++3gd0i/PDa 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 1826""") 1827 1828##file ez_setup.py 1829EZ_SETUP_PY = convert(""" 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 1896BDaonX65d/fwEjNqlDjLVIvM9X+XVxF7 1897""") 1898 1899##file distribute_setup.py 1900DISTRIBUTE_SETUP_PY = convert(""" 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 1980""") 1981 1982##file activate.sh 1983ACTIVATE_SH = convert(""" 1984eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9 1985H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq 1986DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs 1987cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY 1988G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T 1989EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs 1990wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG 19915eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/ 1992JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR 1993huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx 1994Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L 1995Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw 1996WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX 1997LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2 1998""") 1999 2000##file activate.fish 2001ACTIVATE_FISH = convert(""" 2002eJydVm1v4jgQ/s6vmA1wBxUE7X2stJVYlVWR2lK13d6d9laRk0yIr8HmbIe0++tvnIQQB9pbXT5A 2003Ys/LM55nZtyHx5RrSHiGsMm1gRAh1xhDwU0Kng8hFzMWGb5jBv2E69SDs0TJDdj3MxilxmzPZzP7 2004pVPMMl+q9bjXh1eZQ8SEkAZULoAbiLnCyGSvvV6SC7IoBcS4Nw0wjcFbvJDcjiuTswzFDpiIQaHJ 2005lQAjQUi1YRmUboC2uZJig8J4PaCnT5IaDcgsbm/CjinOwgx1KcUTMEhhTgV4g2B1fRk8Le8fv86v 2006g7v545UHpZB9rKnp+gXsMhxLunIIpwVQxP/l9c/Hq9Xt1epm4R27bva6AJqN92G4YhbMG2i+LB+u 2007grv71c3dY7B6WtzfLy9bePbp0taDTXSwJQJszUnnp0y57mvpPcrF7ZODyhswtd59+/jdgw+fwBNS 2008xLSscksUPIDqwwNmCez3PpxGeyBYg6HE0YdcWBxcKczYzuVJi5Wu915vn5oWePCCoPUZBN5B7IgV 2009MCi54ZDLG7TUZ0HweXkb3M5vFmSpFm/gthhBx0UrveoPpv9AJ9unIbQYdUoe21bKg2q48sPFGVwu 2010H+afrxd1qvclaNlRFyh1EQ2sSccEuNAGWQwysfVpz1tPajUqbqJUnEcIJkWo6OXDaodK8ZiLdbmM 2011L1wb+9H0D+pcyPSrX5u5kgWSygRYXCnJUi/KKcuU4cqsAyTKZBiissLc7NFwizvjxtieKBVCIdWz 2012fzilzPaYyljZN0cGN1v7NnaIPNCGmVy3GKuJaQ6iVjE1Qfm+36hglErwmnAD8hu0dDy4uICBA8ZV 2013pQr/q/+O0KFW2kjelu9Dgb9SDBsWV4F4x5CswgS0zBVlk5tDMP5bVtUGpslbm81Lu2sdKq7uNMGh 2014MVQ4fy9xhogC1lS5guhISa0DlBWv0O8odT6/LP+4WZzDV6FzIkEqC0uolGZSZoMnlpxplmD2euaT 2015O4hkTpPnbztDccey0bhjDaBIqaWQa0uwEtQEwtyU56i4fq54F9IE3ORR6mKriODM4XOYZwaVYLYz 20167SPbKkz4i7VkB6/Ot1upDE3znNqYKpM8raa0Bx8vfvntJ32UENsM4aI6gJL+jJwhxhh3jVIDOcpi 2017m0r2hmEtS8XXXNBk71QCDXTBNhhPiHX2LtHkrVIlhoEshH/EZgdq53Eirqs5iFKMnkOmqZTtr3Xq 2018djvPTWZT4S3NT5aVLgurMPUWI07BRVYqkQrmtCKohNY8qu9EdACoT6ki0a66XxVF4f9AQ3W38yO5 2019mWmZmIIpnDFrbXakvKWeZhLwhvrbUH8fahhqD0YUcBDJjEBMQwiznE4y5QbHrbhHBOnUAYzb2tVN 2020jJa65e+eE2Ya30E2GurxUP8ssA6e/wOnvo3V78d3vTcvMB3n7l3iX1JXWqk= 2021""") 2022 2023##file activate.csh 2024ACTIVATE_CSH = convert(""" 2025eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49 2026XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp 2027kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u 2028pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx 2029sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM 2030yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu 2031E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF 2032lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7 2033r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo= 2034""") 2035 2036##file activate.bat 2037ACTIVATE_BAT = convert(""" 2038eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8 2039qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug 2040sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU 2041ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu 2042""") 2043 2044##file deactivate.bat 2045DEACTIVATE_BAT = convert(""" 2046eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q 2047FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL 2048i2dASrm4rFz9XLgAwJNbyQ== 2049""") 2050 2051##file distutils-init.py 2052DISTUTILS_INIT = convert(""" 2053eJytV92L4zYQf/dfMU0ottuse7RvC6FQrg8Lxz2Ugz4si9HacqKuIxlJ2ST313dG8odkO9d7aGBB 2054luZLv/nNjFacOqUtKJMIvzK3cXlhWgp5MDBsqK5SNYftsBAGpLLA4F1oe2Ytl+9wUvW55TswCi4c 2055KibhbFDSglXQCFmDPXIwtm7FawLRbwtPzg2T9gf4gupKv4GS0N262w7V0NvpbCy8cvTo3eAus6C5 2056ETU3ICQZX1hFTw/dzR6V/AW1RCN4/XAtbsVXqIXmlVX6liS4lOzEYY9QFB2zx6LfoSNjz1a0pqT9 2057QOIfJWQ2E888NEVZNqLlZZnvIB0NpHkimlFdKn2iRRY7yGG/CCJb6Iz280d34SFXBS2yEYPNF0Q7 2058yM7oCjpWvbEDQmnhRwOs6zjThpKE8HogwRAgraqYFZgGZvzmzVh+mgz9vskT3hruwyjdFcqyENJw 2059bbMPO5jdzonxK68QKT7B57CMRRG5shRSWDTX3dI8LzRndZbnSWL1zfvriUmK4TcGWSnZiEPCrxXv 2060bM+sP7VW2is2WgWXCO3sAu3Rzysz3FiNCA8WPyM4gb1JAAmCiyTZbhFjWx3h9SzauuRXC9MFoVbc 2061yNTCm1QXOOIfIn/g1kGMhDUBN72hI5XCBQtIXQw8UEEdma6Jaz4vJIJ51Orc15hzzmu6TdFp3ogr 2062Aof0c98tsw1SiaiWotHffk3XYCkqdToxWRfTFXqgpg2khcLluOHMVC0zZhLKIomesfSreUNNgbXi 2063Ky9VRzwzkBneNoGQyyvGjbsFQqOZvpWIjqH281lJ/jireFgR3cPzSyTGWzQpDNIU+03Fs4XKLkhp 2064/n0uFnuF6VphB44b3uWRneSbBoMSioqE8oeF0JY+qTvYfEK+bPLYdoR4McfYQ7wMZj39q0kfP8q+ 2065FfsymO0GzNlPh644Jje06ulqHpOEQqdJUfoidI2O4CWx4qOglLye6RrFQirpCRXvhoRqXH3sYdVJ 2066AItvc+VUsLO2v2hVAWrNIfVGtkG351cUMNncbh/WdowtSPtCdkzYFv6mwYc9o2Jt68ud6wectBr8 2067hYAulPSlgzH44YbV3ikjrulEaNJxt+/H3wZ7bXSXje/YY4tfVVrVmUstaDwwOBLMg6iduDB0lMVC 2068UyzYx7Ab4kjCqdViEJmDcdk/SKbgsjYXgfMznUWcrtS4z4fmJ/XOM1LPk/iIpqass5XwNbdnLb1Y 20698h3ERXSWZI6rZJxKs1LBqVH65w0Oy4ra0CBYxEeuOMbDmV5GI6E0Ha/wgVTtkX0+OXvqsD02CKLf 2070XHbeft85D7tTCMYy2Njp4DJP7gWJr6paVWXZ1+/6YXLv/iE0M90FktiI7yFJD9e7SOLhEkkaMTUO 2071azq9i2woBNR0/0eoF1HFMf0H8ChxH/jgcB34GZIz3Qn4/vid+VEamQrOVqAPTrOfmD4MPdVh09tb 20728dLLjvh/61lEP4yW5vJaH4vHcevG8agXvzPGoOhhXNncpTr99PTHx6e/UvffFLaxUSjuSeP286Dw 2073gtEMcW1xKr/he4/6IQ6FUXP+0gkioHY5iwC9Eyx3HKO7af0zPPe+XyLn7fAY78k4aiR387bCr5XT 20745C4rFgwLGfMvJuAMew== 2075""") 2076 2077##file distutils.cfg 2078DISTUTILS_CFG = convert(""" 2079eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH 2080xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg 20819FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q= 2082""") 2083 2084##file activate_this.py 2085ACTIVATE_THIS = convert(""" 2086eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ 2087VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a 2088Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE 2089qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX 20904lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7 2091HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n 2092xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96 20931Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI 20943vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU= 2095""") 2096 2097if __name__ == '__main__': 2098 main() 2099 2100## TODO: 2101## Copy python.exe.manifest 2102## Monkeypatch distutils.sysconfig 2103