1#!/usr/bin/env python 2"""Create a "virtual" Python installation""" 3 4# fmt: off 5import os # isort:skip 6import sys # isort:skip 7 8# If we are running in a new interpreter to create a virtualenv, 9# we do NOT want paths from our existing location interfering with anything, 10# So we remove this file's directory from sys.path - most likely to be 11# the previous interpreter's site-packages. Solves #705, #763, #779 12 13 14if os.environ.get("VIRTUALENV_INTERPRETER_RUNNING"): 15 for path in sys.path[:]: 16 if os.path.realpath(os.path.dirname(__file__)) == os.path.realpath(path): 17 sys.path.remove(path) 18# fmt: on 19 20import ast 21import base64 22import codecs 23import contextlib 24import distutils.spawn 25import distutils.sysconfig 26import errno 27import glob 28import logging 29import optparse 30import os 31import re 32import shutil 33import struct 34import subprocess 35import sys 36import tempfile 37import textwrap 38import zipfile 39import zlib 40from distutils.util import strtobool 41from os.path import join 42 43try: 44 import ConfigParser 45except ImportError: 46 # noinspection PyPep8Naming 47 import configparser as ConfigParser 48 49__version__ = "16.7.5" 50virtualenv_version = __version__ # legacy 51DEBUG = os.environ.get("_VIRTUALENV_DEBUG", None) == "1" 52if sys.version_info < (2, 7): 53 print("ERROR: {}".format(sys.exc_info()[1])) 54 print("ERROR: this script requires Python 2.7 or greater.") 55 sys.exit(101) 56 57HERE = os.path.dirname(os.path.abspath(__file__)) 58IS_ZIPAPP = os.path.isfile(HERE) 59 60try: 61 # noinspection PyUnresolvedReferences,PyUnboundLocalVariable 62 basestring 63except NameError: 64 basestring = str 65 66VERSION = "{}.{}".format(*sys.version_info) 67PY_VERSION = "python{}.{}".format(*sys.version_info) 68 69IS_PYPY = hasattr(sys, "pypy_version_info") 70IS_WIN = sys.platform == "win32" 71IS_CYGWIN = sys.platform == "cygwin" 72IS_DARWIN = sys.platform == "darwin" 73ABI_FLAGS = getattr(sys, "abiflags", "") 74 75USER_DIR = os.path.expanduser("~") 76if IS_WIN: 77 DEFAULT_STORAGE_DIR = os.path.join(USER_DIR, "virtualenv") 78else: 79 DEFAULT_STORAGE_DIR = os.path.join(USER_DIR, ".virtualenv") 80DEFAULT_CONFIG_FILE = os.path.join(DEFAULT_STORAGE_DIR, "virtualenv.ini") 81 82if IS_PYPY: 83 EXPECTED_EXE = "pypy" 84else: 85 EXPECTED_EXE = "python" 86 87# Return a mapping of version -> Python executable 88# Only provided for Windows, where the information in the registry is used 89if not IS_WIN: 90 91 def get_installed_pythons(): 92 return {} 93 94 95else: 96 try: 97 import winreg 98 except ImportError: 99 # noinspection PyUnresolvedReferences 100 import _winreg as winreg 101 102 def get_installed_pythons(): 103 final_exes = dict() 104 105 # Grab exes from 32-bit registry view 106 exes = _get_installed_pythons_for_view("-32", winreg.KEY_WOW64_32KEY) 107 # Grab exes from 64-bit registry view 108 exes_64 = _get_installed_pythons_for_view("-64", winreg.KEY_WOW64_64KEY) 109 # Check if exes are unique 110 if set(exes.values()) != set(exes_64.values()): 111 exes.update(exes_64) 112 113 # Create dict with all versions found 114 for version, bitness in sorted(exes): 115 exe = exes[(version, bitness)] 116 # Add minor version (X.Y-32 or X.Y-64) 117 final_exes[version + bitness] = exe 118 # Add minor extensionless version (X.Y); 3.2-64 wins over 3.2-32 119 final_exes[version] = exe 120 # Add major version (X-32 or X-64) 121 final_exes[version[0] + bitness] = exe 122 # Add major extensionless version (X); 3.3-32 wins over 3.2-64 123 final_exes[version[0]] = exe 124 125 return final_exes 126 127 def _get_installed_pythons_for_view(bitness, view): 128 exes = dict() 129 # If both system and current user installations are found for a 130 # particular Python version, the current user one is used 131 for key in (winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER): 132 try: 133 python_core = winreg.OpenKey(key, "Software\\Python\\PythonCore", 0, view | winreg.KEY_READ) 134 except WindowsError: 135 # No registered Python installations 136 continue 137 i = 0 138 while True: 139 try: 140 version = winreg.EnumKey(python_core, i) 141 i += 1 142 try: 143 at_path = winreg.QueryValue(python_core, "{}\\InstallPath".format(version)) 144 except WindowsError: 145 continue 146 # Remove bitness from version 147 if version.endswith(bitness): 148 version = version[: -len(bitness)] 149 exes[(version, bitness)] = join(at_path, "python.exe") 150 except WindowsError: 151 break 152 winreg.CloseKey(python_core) 153 154 return exes 155 156 157REQUIRED_MODULES = [ 158 "os", 159 "posix", 160 "posixpath", 161 "nt", 162 "ntpath", 163 "genericpath", 164 "fnmatch", 165 "locale", 166 "encodings", 167 "codecs", 168 "stat", 169 "UserDict", 170 "readline", 171 "copy_reg", 172 "types", 173 "re", 174 "sre", 175 "sre_parse", 176 "sre_constants", 177 "sre_compile", 178 "zlib", 179] 180 181REQUIRED_FILES = ["lib-dynload", "config"] 182 183MAJOR, MINOR = sys.version_info[:2] 184if MAJOR == 2: 185 if MINOR >= 6: 186 REQUIRED_MODULES.extend(["warnings", "linecache", "_abcoll", "abc"]) 187 if MINOR >= 7: 188 REQUIRED_MODULES.extend(["_weakrefset"]) 189elif MAJOR == 3: 190 # Some extra modules are needed for Python 3, but different ones 191 # for different versions. 192 REQUIRED_MODULES.extend( 193 [ 194 "_abcoll", 195 "warnings", 196 "linecache", 197 "abc", 198 "io", 199 "_weakrefset", 200 "copyreg", 201 "tempfile", 202 "random", 203 "__future__", 204 "collections", 205 "keyword", 206 "tarfile", 207 "shutil", 208 "struct", 209 "copy", 210 "tokenize", 211 "token", 212 "functools", 213 "heapq", 214 "bisect", 215 "weakref", 216 "reprlib", 217 ] 218 ) 219 if MINOR >= 2: 220 REQUIRED_FILES[-1] = "config-{}".format(MAJOR) 221 if MINOR >= 3: 222 import sysconfig 223 224 platform_dir = sysconfig.get_config_var("PLATDIR") 225 REQUIRED_FILES.append(platform_dir) 226 REQUIRED_MODULES.extend(["base64", "_dummy_thread", "hashlib", "hmac", "imp", "importlib", "rlcompleter"]) 227 if MINOR >= 4: 228 REQUIRED_MODULES.extend(["operator", "_collections_abc", "_bootlocale"]) 229 if MINOR >= 6: 230 REQUIRED_MODULES.extend(["enum"]) 231 232if IS_PYPY: 233 # these are needed to correctly display the exceptions that may happen 234 # during the bootstrap 235 REQUIRED_MODULES.extend(["traceback", "linecache"]) 236 237 if MAJOR == 3: 238 # _functools is needed to import locale during stdio initialization and 239 # needs to be copied on PyPy because it's not built in 240 REQUIRED_MODULES.append("_functools") 241 242 243class Logger(object): 244 245 """ 246 Logging object for use in command-line script. Allows ranges of 247 levels, to avoid some redundancy of displayed information. 248 """ 249 250 DEBUG = logging.DEBUG 251 INFO = logging.INFO 252 NOTIFY = (logging.INFO + logging.WARN) / 2 253 WARN = WARNING = logging.WARN 254 ERROR = logging.ERROR 255 FATAL = logging.FATAL 256 257 LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL] 258 259 def __init__(self, consumers): 260 self.consumers = consumers 261 self.indent = 0 262 self.in_progress = None 263 self.in_progress_hanging = False 264 265 def debug(self, msg, *args, **kw): 266 self.log(self.DEBUG, msg, *args, **kw) 267 268 def info(self, msg, *args, **kw): 269 self.log(self.INFO, msg, *args, **kw) 270 271 def notify(self, msg, *args, **kw): 272 self.log(self.NOTIFY, msg, *args, **kw) 273 274 def warn(self, msg, *args, **kw): 275 self.log(self.WARN, msg, *args, **kw) 276 277 def error(self, msg, *args, **kw): 278 self.log(self.ERROR, msg, *args, **kw) 279 280 def fatal(self, msg, *args, **kw): 281 self.log(self.FATAL, msg, *args, **kw) 282 283 def log(self, level, msg, *args, **kw): 284 if args: 285 if kw: 286 raise TypeError("You may give positional or keyword arguments, not both") 287 args = args or kw 288 rendered = None 289 for consumer_level, consumer in self.consumers: 290 if self.level_matches(level, consumer_level): 291 if self.in_progress_hanging and consumer in (sys.stdout, sys.stderr): 292 self.in_progress_hanging = False 293 print("") 294 sys.stdout.flush() 295 if rendered is None: 296 if args: 297 rendered = msg % args 298 else: 299 rendered = msg 300 rendered = " " * self.indent + rendered 301 if hasattr(consumer, "write"): 302 consumer.write(rendered + "\n") 303 else: 304 consumer(rendered) 305 306 def start_progress(self, msg): 307 assert not self.in_progress, "Tried to start_progress({!r}) while in_progress {!r}".format( 308 msg, self.in_progress 309 ) 310 if self.level_matches(self.NOTIFY, self._stdout_level()): 311 print(msg) 312 sys.stdout.flush() 313 self.in_progress_hanging = True 314 else: 315 self.in_progress_hanging = False 316 self.in_progress = msg 317 318 def end_progress(self, msg="done."): 319 assert self.in_progress, "Tried to end_progress without start_progress" 320 if self.stdout_level_matches(self.NOTIFY): 321 if not self.in_progress_hanging: 322 # Some message has been printed out since start_progress 323 print("...{}{}".format(self.in_progress, msg)) 324 sys.stdout.flush() 325 else: 326 print(msg) 327 sys.stdout.flush() 328 self.in_progress = None 329 self.in_progress_hanging = False 330 331 def show_progress(self): 332 """If we are in a progress scope, and no log messages have been 333 shown, write out another '.'""" 334 if self.in_progress_hanging: 335 print(".") 336 sys.stdout.flush() 337 338 def stdout_level_matches(self, level): 339 """Returns true if a message at this level will go to stdout""" 340 return self.level_matches(level, self._stdout_level()) 341 342 def _stdout_level(self): 343 """Returns the level that stdout runs at""" 344 for level, consumer in self.consumers: 345 if consumer is sys.stdout: 346 return level 347 return self.FATAL 348 349 @staticmethod 350 def level_matches(level, consumer_level): 351 """ 352 >>> l = Logger([]) 353 >>> l.level_matches(3, 4) 354 False 355 >>> l.level_matches(3, 2) 356 True 357 >>> l.level_matches(slice(None, 3), 3) 358 False 359 >>> l.level_matches(slice(None, 3), 2) 360 True 361 >>> l.level_matches(slice(1, 3), 1) 362 True 363 >>> l.level_matches(slice(2, 3), 1) 364 False 365 """ 366 if isinstance(level, slice): 367 start, stop = level.start, level.stop 368 if start is not None and start > consumer_level: 369 return False 370 if stop is not None and stop <= consumer_level: 371 return False 372 return True 373 else: 374 return level >= consumer_level 375 376 @classmethod 377 def level_for_integer(cls, level): 378 levels = cls.LEVELS 379 if level < 0: 380 return levels[0] 381 if level >= len(levels): 382 return levels[-1] 383 return levels[level] 384 385 386# create a silent logger just to prevent this from being undefined 387# will be overridden with requested verbosity main() is called. 388logger = Logger([(Logger.LEVELS[-1], sys.stdout)]) 389 390 391def mkdir(at_path): 392 if not os.path.exists(at_path): 393 logger.info("Creating %s", at_path) 394 os.makedirs(at_path) 395 else: 396 logger.info("Directory %s already exists", at_path) 397 398 399def copy_file_or_folder(src, dest, symlink=True): 400 if os.path.isdir(src): 401 shutil.copytree(src, dest, symlink) 402 else: 403 shutil.copy2(src, dest) 404 405 406def copyfile(src, dest, symlink=True): 407 if not os.path.exists(src): 408 # Some bad symlink in the src 409 logger.warn("Cannot find file %s (bad symlink)", src) 410 return 411 if os.path.exists(dest): 412 logger.debug("File %s already exists", dest) 413 return 414 if not os.path.exists(os.path.dirname(dest)): 415 logger.info("Creating parent directories for %s", os.path.dirname(dest)) 416 os.makedirs(os.path.dirname(dest)) 417 if symlink and hasattr(os, "symlink") and not IS_WIN: 418 logger.info("Symlinking %s", dest) 419 try: 420 os.symlink(os.path.realpath(src), dest) 421 except (OSError, NotImplementedError): 422 logger.info("Symlinking failed, copying to %s", dest) 423 copy_file_or_folder(src, dest, symlink) 424 else: 425 logger.info("Copying to %s", dest) 426 copy_file_or_folder(src, dest, symlink) 427 428 429def writefile(dest, content, overwrite=True): 430 if not os.path.exists(dest): 431 logger.info("Writing %s", dest) 432 with open(dest, "wb") as f: 433 f.write(content.encode("utf-8")) 434 return 435 else: 436 with open(dest, "rb") as f: 437 c = f.read() 438 if c != content.encode("utf-8"): 439 if not overwrite: 440 logger.notify("File %s exists with different content; not overwriting", dest) 441 return 442 logger.notify("Overwriting %s with new content", dest) 443 with open(dest, "wb") as f: 444 f.write(content.encode("utf-8")) 445 else: 446 logger.info("Content %s already in place", dest) 447 448 449def rm_tree(folder): 450 if os.path.exists(folder): 451 logger.notify("Deleting tree %s", folder) 452 shutil.rmtree(folder) 453 else: 454 logger.info("Do not need to delete %s; already gone", folder) 455 456 457def make_exe(fn): 458 if hasattr(os, "chmod"): 459 old_mode = os.stat(fn).st_mode & 0xFFF # 0o7777 460 new_mode = (old_mode | 0x16D) & 0xFFF # 0o555, 0o7777 461 os.chmod(fn, new_mode) 462 logger.info("Changed mode of %s to %s", fn, oct(new_mode)) 463 464 465def _find_file(filename, folders): 466 for folder in reversed(folders): 467 files = glob.glob(os.path.join(folder, filename)) 468 if files and os.path.isfile(files[0]): 469 return True, files[0] 470 return False, filename 471 472 473@contextlib.contextmanager 474def virtualenv_support_dirs(): 475 """Context manager yielding either [virtualenv_support_dir] or []""" 476 477 # normal filesystem installation 478 if os.path.isdir(join(HERE, "virtualenv_support")): 479 yield [join(HERE, "virtualenv_support")] 480 elif IS_ZIPAPP: 481 tmpdir = tempfile.mkdtemp() 482 try: 483 with zipfile.ZipFile(HERE) as zipf: 484 for member in zipf.namelist(): 485 if os.path.dirname(member) == "virtualenv_support": 486 zipf.extract(member, tmpdir) 487 yield [join(tmpdir, "virtualenv_support")] 488 finally: 489 shutil.rmtree(tmpdir) 490 # probably a bootstrap script 491 elif os.path.splitext(os.path.dirname(__file__))[0] != "virtualenv": 492 try: 493 # noinspection PyUnresolvedReferences 494 import virtualenv 495 except ImportError: 496 yield [] 497 else: 498 yield [join(os.path.dirname(virtualenv.__file__), "virtualenv_support")] 499 # we tried! 500 else: 501 yield [] 502 503 504class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter): 505 """ 506 Custom help formatter for use in ConfigOptionParser that updates 507 the defaults before expanding them, allowing them to show up correctly 508 in the help listing 509 """ 510 511 def expand_default(self, option): 512 if self.parser is not None: 513 self.parser.update_defaults(self.parser.defaults) 514 return optparse.IndentedHelpFormatter.expand_default(self, option) 515 516 517class ConfigOptionParser(optparse.OptionParser): 518 """ 519 Custom option parser which updates its defaults by checking the 520 configuration files and environmental variables 521 """ 522 523 def __init__(self, *args, **kwargs): 524 self.config = ConfigParser.RawConfigParser() 525 self.files = self.get_config_files() 526 self.config.read(self.files) 527 optparse.OptionParser.__init__(self, *args, **kwargs) 528 529 @staticmethod 530 def get_config_files(): 531 config_file = os.environ.get("VIRTUALENV_CONFIG_FILE", False) 532 if config_file and os.path.exists(config_file): 533 return [config_file] 534 return [DEFAULT_CONFIG_FILE] 535 536 def update_defaults(self, defaults): 537 """ 538 Updates the given defaults with values from the config files and 539 the environ. Does a little special handling for certain types of 540 options (lists). 541 """ 542 # Then go and look for the other sources of configuration: 543 config = {} 544 # 1. config files 545 config.update(dict(self.get_config_section("virtualenv"))) 546 # 2. environmental variables 547 config.update(dict(self.get_environ_vars())) 548 # Then set the options with those values 549 for key, val in config.items(): 550 key = key.replace("_", "-") 551 if not key.startswith("--"): 552 key = "--{}".format(key) # only prefer long opts 553 option = self.get_option(key) 554 if option is not None: 555 # ignore empty values 556 if not val: 557 continue 558 # handle multiline configs 559 if option.action == "append": 560 val = val.split() 561 else: 562 option.nargs = 1 563 if option.action == "store_false": 564 val = not strtobool(val) 565 elif option.action in ("store_true", "count"): 566 val = strtobool(val) 567 try: 568 val = option.convert_value(key, val) 569 except optparse.OptionValueError: 570 e = sys.exc_info()[1] 571 print("An error occurred during configuration: {!r}".format(e)) 572 sys.exit(3) 573 defaults[option.dest] = val 574 return defaults 575 576 def get_config_section(self, name): 577 """ 578 Get a section of a configuration 579 """ 580 if self.config.has_section(name): 581 return self.config.items(name) 582 return [] 583 584 def get_environ_vars(self, prefix="VIRTUALENV_"): 585 """ 586 Returns a generator with all environmental vars with prefix VIRTUALENV 587 """ 588 for key, val in os.environ.items(): 589 if key.startswith(prefix): 590 yield (key.replace(prefix, "").lower(), val) 591 592 def get_default_values(self): 593 """ 594 Overriding to make updating the defaults after instantiation of 595 the option parser possible, update_defaults() does the dirty work. 596 """ 597 if not self.process_default_values: 598 # Old, pre-Optik 1.5 behaviour. 599 return optparse.Values(self.defaults) 600 601 defaults = self.update_defaults(self.defaults.copy()) # ours 602 for option in self._get_all_options(): 603 default = defaults.get(option.dest) 604 if isinstance(default, basestring): 605 opt_str = option.get_opt_string() 606 defaults[option.dest] = option.check_value(opt_str, default) 607 return optparse.Values(defaults) 608 609 610def main(): 611 parser = ConfigOptionParser( 612 version=virtualenv_version, usage="%prog [OPTIONS] DEST_DIR", formatter=UpdatingDefaultsHelpFormatter() 613 ) 614 615 parser.add_option( 616 "-v", "--verbose", action="count", dest="verbose", default=5 if DEBUG else 0, help="Increase verbosity." 617 ) 618 619 parser.add_option("-q", "--quiet", action="count", dest="quiet", default=0, help="Decrease verbosity.") 620 621 parser.add_option( 622 "-p", 623 "--python", 624 dest="python", 625 metavar="PYTHON_EXE", 626 help="The Python interpreter to use, e.g., --python=python3.5 will use the python3.5 " 627 "interpreter to create the new environment. The default is the interpreter that " 628 "virtualenv was installed with ({})".format(sys.executable), 629 ) 630 631 parser.add_option( 632 "--clear", dest="clear", action="store_true", help="Clear out the non-root install and start from scratch." 633 ) 634 635 parser.set_defaults(system_site_packages=False) 636 parser.add_option( 637 "--no-site-packages", 638 dest="system_site_packages", 639 action="store_false", 640 help="DEPRECATED. Retained only for backward compatibility. " 641 "Not having access to global site-packages is now the default behavior.", 642 ) 643 644 parser.add_option( 645 "--system-site-packages", 646 dest="system_site_packages", 647 action="store_true", 648 help="Give the virtual environment access to the global site-packages.", 649 ) 650 651 parser.add_option( 652 "--always-copy", 653 dest="symlink", 654 action="store_false", 655 default=True, 656 help="Always copy files rather than symlinking.", 657 ) 658 659 parser.add_option( 660 "--relocatable", 661 dest="relocatable", 662 action="store_true", 663 help="Make an EXISTING virtualenv environment relocatable. " 664 "This fixes up scripts and makes all .pth files relative.", 665 ) 666 667 parser.add_option( 668 "--no-setuptools", 669 dest="no_setuptools", 670 action="store_true", 671 help="Do not install setuptools in the new virtualenv.", 672 ) 673 674 parser.add_option("--no-pip", dest="no_pip", action="store_true", help="Do not install pip in the new virtualenv.") 675 676 parser.add_option( 677 "--no-wheel", dest="no_wheel", action="store_true", help="Do not install wheel in the new virtualenv." 678 ) 679 680 parser.add_option( 681 "--extra-search-dir", 682 dest="search_dirs", 683 action="append", 684 metavar="DIR", 685 default=[], 686 help="Directory to look for setuptools/pip distributions in. " "This option can be used multiple times.", 687 ) 688 689 parser.add_option( 690 "--download", 691 dest="download", 692 default=True, 693 action="store_true", 694 help="Download pre-installed packages from PyPI.", 695 ) 696 697 parser.add_option( 698 "--no-download", 699 "--never-download", 700 dest="download", 701 action="store_false", 702 help="Do not download pre-installed packages from PyPI.", 703 ) 704 705 parser.add_option("--prompt", dest="prompt", help="Provides an alternative prompt prefix for this environment.") 706 707 parser.add_option( 708 "--setuptools", 709 dest="setuptools", 710 action="store_true", 711 help="DEPRECATED. Retained only for backward compatibility. This option has no effect.", 712 ) 713 714 parser.add_option( 715 "--distribute", 716 dest="distribute", 717 action="store_true", 718 help="DEPRECATED. Retained only for backward compatibility. This option has no effect.", 719 ) 720 721 parser.add_option( 722 "--unzip-setuptools", 723 action="store_true", 724 help="DEPRECATED. Retained only for backward compatibility. This option has no effect.", 725 ) 726 727 if "extend_parser" in globals(): 728 # noinspection PyUnresolvedReferences 729 extend_parser(parser) # noqa: F821 730 731 options, args = parser.parse_args() 732 733 global logger 734 735 if "adjust_options" in globals(): 736 # noinspection PyUnresolvedReferences 737 adjust_options(options, args) # noqa: F821 738 739 verbosity = options.verbose - options.quiet 740 logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)]) 741 742 def should_reinvoke(options): 743 """Do we need to reinvoke ourself?""" 744 # Did the user specify the --python option? 745 if options.python and not os.environ.get("VIRTUALENV_INTERPRETER_RUNNING"): 746 interpreter = resolve_interpreter(options.python) 747 if interpreter != sys.executable: 748 # The user specified a different interpreter, so we have to reinvoke. 749 return interpreter 750 751 # At this point, we know the user wants to use sys.executable to create the 752 # virtual environment. But on Windows, sys.executable may be a venv redirector, 753 # in which case we still need to locate the underlying actual interpreter, and 754 # reinvoke using that. 755 if IS_WIN: 756 # OK. Now things get really fun... 757 # 758 # If we are running from a venv, with a redirector, then what happens is as 759 # follows: 760 # 761 # 1. The redirector sets __PYVENV_LAUNCHER__ in the environment to point 762 # to the redirector executable. 763 # 2. The redirector launches the "base" Python (from the home value in 764 # pyvenv.cfg). 765 # 3. The base Python executable sees __PYVENV_LAUNCHER__ in the environment 766 # and sets sys.executable to that value. 767 # 4. If site.py gets run, it sees __PYVENV_LAUNCHER__, and sets 768 # sys._base_executable to _winapi.GetModuleFileName(0) and removes 769 # __PYVENV_LAUNCHER__. 770 # 771 # Unfortunately, that final step (site.py) may not happen. There are 2 key 772 # times when that is the case: 773 # 774 # 1. Python 3.7.2, which had the redirector but not the site.py code. 775 # 2. Running a venv from a virtualenv, which uses virtualenv's custom 776 # site.py. 777 # 778 # So, we check for sys._base_executable, but if it's not present and yet we 779 # have __PYVENV_LAUNCHER__, we do what site.py would have done and get our 780 # interpreter from GetModuleFileName(0). We also remove __PYVENV_LAUNCHER__ 781 # from the environment, to avoid loops (actually, mainly because site.py 782 # does so, and my head hurts enough buy now that I just want to be safe!) 783 784 # In Python 3.7.4, the rules changed so that sys._base_executable is always 785 # set. So we now only return sys._base_executable if it's set *and does not 786 # match sys.executable* (we still have to check that it's set, as we need to 787 # support Python 3.7.3 and earlier). 788 789 # Phew. 790 791 if getattr(sys, "_base_executable", sys.executable) != sys.executable: 792 return sys._base_executable 793 794 if "__PYVENV_LAUNCHER__" in os.environ: 795 import _winapi 796 797 del os.environ["__PYVENV_LAUNCHER__"] 798 return _winapi.GetModuleFileName(0) 799 800 # We don't need to reinvoke 801 return None 802 803 interpreter = should_reinvoke(options) 804 if interpreter is None: 805 # We don't need to reinvoke - if the user asked us to, tell them why we 806 # aren't. 807 if options.python: 808 logger.warn("Already using interpreter {}".format(sys.executable)) 809 else: 810 env = os.environ.copy() 811 logger.notify("Running virtualenv with interpreter {}".format(interpreter)) 812 env["VIRTUALENV_INTERPRETER_RUNNING"] = "true" 813 # Remove the variable __PYVENV_LAUNCHER__ if it's present, as it causes the 814 # interpreter to redirect back to the virtual environment. 815 if "__PYVENV_LAUNCHER__" in env: 816 del env["__PYVENV_LAUNCHER__"] 817 file = __file__ 818 if file.endswith(".pyc"): 819 file = file[:-1] 820 elif IS_ZIPAPP: 821 file = HERE 822 sub_process_call = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env) 823 raise SystemExit(sub_process_call.wait()) 824 825 if not args: 826 print("You must provide a DEST_DIR") 827 parser.print_help() 828 sys.exit(2) 829 if len(args) > 1: 830 print("There must be only one argument: DEST_DIR (you gave {})".format(" ".join(args))) 831 parser.print_help() 832 sys.exit(2) 833 834 home_dir = args[0] 835 836 if os.path.exists(home_dir) and os.path.isfile(home_dir): 837 logger.fatal("ERROR: File already exists and is not a directory.") 838 logger.fatal("Please provide a different path or delete the file.") 839 sys.exit(3) 840 841 if os.pathsep in home_dir: 842 logger.fatal("ERROR: target path contains the operating system path separator '{}'".format(os.pathsep)) 843 logger.fatal("This is not allowed as would make the activation scripts unusable.".format(os.pathsep)) 844 sys.exit(3) 845 846 if os.environ.get("WORKING_ENV"): 847 logger.fatal("ERROR: you cannot run virtualenv while in a working env") 848 logger.fatal("Please deactivate your working env, then re-run this script") 849 sys.exit(3) 850 851 if "PYTHONHOME" in os.environ: 852 logger.warn("PYTHONHOME is set. You *must* activate the virtualenv before using it") 853 del os.environ["PYTHONHOME"] 854 855 if options.relocatable: 856 make_environment_relocatable(home_dir) 857 return 858 859 with virtualenv_support_dirs() as search_dirs: 860 create_environment( 861 home_dir, 862 site_packages=options.system_site_packages, 863 clear=options.clear, 864 prompt=options.prompt, 865 search_dirs=search_dirs + options.search_dirs, 866 download=options.download, 867 no_setuptools=options.no_setuptools, 868 no_pip=options.no_pip, 869 no_wheel=options.no_wheel, 870 symlink=options.symlink, 871 ) 872 if "after_install" in globals(): 873 # noinspection PyUnresolvedReferences 874 after_install(options, home_dir) # noqa: F821 875 876 877def call_subprocess( 878 cmd, 879 show_stdout=True, 880 filter_stdout=None, 881 cwd=None, 882 raise_on_return_code=True, 883 extra_env=None, 884 remove_from_env=None, 885 stdin=None, 886): 887 cmd_parts = [] 888 for part in cmd: 889 if len(part) > 45: 890 part = part[:20] + "..." + part[-20:] 891 if " " in part or "\n" in part or '"' in part or "'" in part: 892 part = '"{}"'.format(part.replace('"', '\\"')) 893 if hasattr(part, "decode"): 894 try: 895 part = part.decode(sys.getdefaultencoding()) 896 except UnicodeDecodeError: 897 part = part.decode(sys.getfilesystemencoding()) 898 cmd_parts.append(part) 899 cmd_desc = " ".join(cmd_parts) 900 if show_stdout: 901 stdout = None 902 else: 903 stdout = subprocess.PIPE 904 logger.debug("Running command {}".format(cmd_desc)) 905 if extra_env or remove_from_env: 906 env = os.environ.copy() 907 if extra_env: 908 env.update(extra_env) 909 if remove_from_env: 910 for var_name in remove_from_env: 911 env.pop(var_name, None) 912 else: 913 env = None 914 try: 915 proc = subprocess.Popen( 916 cmd, 917 stderr=subprocess.STDOUT, 918 stdin=None if stdin is None else subprocess.PIPE, 919 stdout=stdout, 920 cwd=cwd, 921 env=env, 922 ) 923 except Exception: 924 e = sys.exc_info()[1] 925 logger.fatal("Error {} while executing command {}".format(e, cmd_desc)) 926 raise 927 all_output = [] 928 if stdout is not None: 929 if stdin is not None: 930 with proc.stdin: 931 proc.stdin.write(stdin) 932 933 encoding = sys.getdefaultencoding() 934 fs_encoding = sys.getfilesystemencoding() 935 with proc.stdout as stdout: 936 while 1: 937 line = stdout.readline() 938 try: 939 line = line.decode(encoding) 940 except UnicodeDecodeError: 941 line = line.decode(fs_encoding) 942 if not line: 943 break 944 line = line.rstrip() 945 all_output.append(line) 946 if filter_stdout: 947 level = filter_stdout(line) 948 if isinstance(level, tuple): 949 level, line = level 950 logger.log(level, line) 951 if not logger.stdout_level_matches(level): 952 logger.show_progress() 953 else: 954 logger.info(line) 955 else: 956 proc.communicate(stdin) 957 proc.wait() 958 if proc.returncode: 959 if raise_on_return_code: 960 if all_output: 961 logger.notify("Complete output from command {}:".format(cmd_desc)) 962 logger.notify("\n".join(all_output) + "\n----------------------------------------") 963 raise OSError("Command {} failed with error code {}".format(cmd_desc, proc.returncode)) 964 else: 965 logger.warn("Command {} had error code {}".format(cmd_desc, proc.returncode)) 966 return all_output 967 968 969def filter_install_output(line): 970 if line.strip().startswith("running"): 971 return Logger.INFO 972 return Logger.DEBUG 973 974 975def find_wheels(projects, search_dirs): 976 """Find wheels from which we can import PROJECTS. 977 978 Scan through SEARCH_DIRS for a wheel for each PROJECT in turn. Return 979 a list of the first wheel found for each PROJECT 980 """ 981 982 wheels = [] 983 984 # Look through SEARCH_DIRS for the first suitable wheel. Don't bother 985 # about version checking here, as this is simply to get something we can 986 # then use to install the correct version. 987 for project in projects: 988 for dirname in search_dirs: 989 # This relies on only having "universal" wheels available. 990 # The pattern could be tightened to require -py2.py3-none-any.whl. 991 files = glob.glob(os.path.join(dirname, "{}-*.whl".format(project))) 992 if files: 993 versions = sorted( 994 [(tuple(int(i) for i in os.path.basename(f).split("-")[1].split(".")), f) for f in files] 995 ) 996 if project == "pip" and sys.version_info[0:2] == (3, 4): 997 wheel = next(p for v, p in versions if v <= (19, 1, 1)) 998 else: 999 wheel = versions[0][1] 1000 wheels.append(wheel) 1001 break 1002 else: 1003 # We're out of luck, so quit with a suitable error 1004 logger.fatal("Cannot find a wheel for {}".format(project)) 1005 1006 return wheels 1007 1008 1009def install_wheel(project_names, py_executable, search_dirs=None, download=False): 1010 if search_dirs is None: 1011 search_dirs_context = virtualenv_support_dirs 1012 else: 1013 1014 @contextlib.contextmanager 1015 def search_dirs_context(): 1016 yield search_dirs 1017 1018 with search_dirs_context() as search_dirs: 1019 _install_wheel_with_search_dir(download, project_names, py_executable, search_dirs) 1020 1021 1022def _install_wheel_with_search_dir(download, project_names, py_executable, search_dirs): 1023 wheels = find_wheels(["setuptools", "pip"], search_dirs) 1024 python_path = os.pathsep.join(wheels) 1025 1026 # PIP_FIND_LINKS uses space as the path separator and thus cannot have paths 1027 # with spaces in them. Convert any of those to local file:// URL form. 1028 try: 1029 from urlparse import urljoin 1030 from urllib import pathname2url 1031 except ImportError: 1032 from urllib.parse import urljoin 1033 from urllib.request import pathname2url 1034 1035 def space_path2url(p): 1036 if " " not in p: 1037 return p 1038 return urljoin("file:", pathname2url(os.path.abspath(p))) 1039 1040 find_links = " ".join(space_path2url(d) for d in search_dirs) 1041 1042 extra_args = ["--ignore-installed", "-v"] 1043 if DEBUG: 1044 extra_args.append("-v") 1045 1046 config = _pip_config(py_executable, python_path) 1047 defined_cert = bool(config.get("install.cert") or config.get(":env:.cert") or config.get("global.cert")) 1048 1049 script = textwrap.dedent( 1050 """ 1051 import sys 1052 import pkgutil 1053 import tempfile 1054 import os 1055 1056 defined_cert = {defined_cert} 1057 1058 try: 1059 from pip._internal import main as _main 1060 cert_data = pkgutil.get_data("pip._vendor.certifi", "cacert.pem") 1061 except ImportError: 1062 from pip import main as _main 1063 cert_data = pkgutil.get_data("pip._vendor.requests", "cacert.pem") 1064 except IOError: 1065 cert_data = None 1066 1067 if not defined_cert and cert_data is not None: 1068 cert_file = tempfile.NamedTemporaryFile(delete=False) 1069 cert_file.write(cert_data) 1070 cert_file.close() 1071 else: 1072 cert_file = None 1073 1074 try: 1075 args = ["install"] + [{extra_args}] 1076 if cert_file is not None: 1077 args += ["--cert", cert_file.name] 1078 args += sys.argv[1:] 1079 1080 sys.exit(_main(args)) 1081 finally: 1082 if cert_file is not None: 1083 os.remove(cert_file.name) 1084 """.format( 1085 defined_cert=defined_cert, extra_args=", ".join(repr(i) for i in extra_args) 1086 ) 1087 ).encode("utf8") 1088 1089 if sys.version_info[0:2] == (3, 4): 1090 at = project_names.index("pip") 1091 project_names[at] = "pip<19.2" 1092 1093 cmd = [py_executable, "-"] + project_names 1094 logger.start_progress("Installing {}...".format(", ".join(project_names))) 1095 logger.indent += 2 1096 1097 env = { 1098 "PYTHONPATH": python_path, 1099 "PIP_FIND_LINKS": find_links, 1100 "PIP_USE_WHEEL": "1", 1101 "PIP_ONLY_BINARY": ":all:", 1102 "PIP_USER": "0", 1103 "PIP_NO_INPUT": "1", 1104 } 1105 1106 if not download: 1107 env["PIP_NO_INDEX"] = "1" 1108 1109 try: 1110 call_subprocess(cmd, show_stdout=False, extra_env=env, stdin=script) 1111 finally: 1112 logger.indent -= 2 1113 logger.end_progress() 1114 1115 1116def _pip_config(py_executable, python_path): 1117 cmd = [py_executable, "-m", "pip", "config", "list"] 1118 config = {} 1119 for line in call_subprocess( 1120 cmd, 1121 show_stdout=False, 1122 extra_env={"PYTHONPATH": python_path}, 1123 remove_from_env=["PIP_VERBOSE", "PIP_QUIET"], 1124 raise_on_return_code=False, 1125 ): 1126 key, _, value = line.partition("=") 1127 if value: 1128 config[key] = ast.literal_eval(value) 1129 return config 1130 1131 1132def create_environment( 1133 home_dir, 1134 site_packages=False, 1135 clear=False, 1136 prompt=None, 1137 search_dirs=None, 1138 download=False, 1139 no_setuptools=False, 1140 no_pip=False, 1141 no_wheel=False, 1142 symlink=True, 1143): 1144 """ 1145 Creates a new environment in ``home_dir``. 1146 1147 If ``site_packages`` is true, then the global ``site-packages/`` 1148 directory will be on the path. 1149 1150 If ``clear`` is true (default False) then the environment will 1151 first be cleared. 1152 """ 1153 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1154 1155 py_executable = os.path.abspath( 1156 install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages=site_packages, clear=clear, symlink=symlink) 1157 ) 1158 1159 install_distutils(home_dir) 1160 1161 to_install = [] 1162 1163 if not no_setuptools: 1164 to_install.append("setuptools") 1165 1166 if not no_pip: 1167 to_install.append("pip") 1168 1169 if not no_wheel: 1170 to_install.append("wheel") 1171 1172 if to_install: 1173 install_wheel(to_install, py_executable, search_dirs, download=download) 1174 1175 install_activate(home_dir, bin_dir, prompt) 1176 1177 install_python_config(home_dir, bin_dir, prompt) 1178 1179 1180def is_executable_file(fpath): 1181 return os.path.isfile(fpath) and is_executable(fpath) 1182 1183 1184def path_locations(home_dir, dry_run=False): 1185 """Return the path locations for the environment (where libraries are, 1186 where scripts go, etc)""" 1187 home_dir = os.path.abspath(home_dir) 1188 lib_dir, inc_dir, bin_dir = None, None, None 1189 # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its 1190 # prefix arg is broken: http://bugs.python.org/issue3386 1191 if IS_WIN: 1192 # Windows has lots of problems with executables with spaces in 1193 # the name; this function will remove them (using the ~1 1194 # format): 1195 if not dry_run: 1196 mkdir(home_dir) 1197 if " " in home_dir: 1198 import ctypes 1199 1200 get_short_path_name = ctypes.windll.kernel32.GetShortPathNameW 1201 size = max(len(home_dir) + 1, 256) 1202 buf = ctypes.create_unicode_buffer(size) 1203 try: 1204 # noinspection PyUnresolvedReferences 1205 u = unicode 1206 except NameError: 1207 u = str 1208 ret = get_short_path_name(u(home_dir), buf, size) 1209 if not ret: 1210 print('Error: the path "{}" has a space in it'.format(home_dir)) 1211 print("We could not determine the short pathname for it.") 1212 print("Exiting.") 1213 sys.exit(3) 1214 home_dir = str(buf.value) 1215 lib_dir = join(home_dir, "Lib") 1216 inc_dir = join(home_dir, "Include") 1217 bin_dir = join(home_dir, "Scripts") 1218 if IS_PYPY: 1219 lib_dir = home_dir 1220 inc_dir = join(home_dir, "include") 1221 bin_dir = join(home_dir, "bin") 1222 elif not IS_WIN: 1223 lib_dir = join(home_dir, "lib", PY_VERSION) 1224 inc_dir = join(home_dir, "include", PY_VERSION + ABI_FLAGS) 1225 bin_dir = join(home_dir, "bin") 1226 return home_dir, lib_dir, inc_dir, bin_dir 1227 1228 1229def change_prefix(filename, dst_prefix): 1230 prefixes = [sys.prefix] 1231 1232 if IS_DARWIN: 1233 prefixes.extend( 1234 ( 1235 os.path.join("/Library/Python", VERSION, "site-packages"), 1236 os.path.join(sys.prefix, "Extras", "lib", "python"), 1237 os.path.join("~", "Library", "Python", VERSION, "site-packages"), 1238 # Python 2.6 no-frameworks 1239 os.path.join("~", ".local", "lib", "python", VERSION, "site-packages"), 1240 # System Python 2.7 on OSX Mountain Lion 1241 os.path.join("~", "Library", "Python", VERSION, "lib", "python", "site-packages"), 1242 ) 1243 ) 1244 1245 if hasattr(sys, "real_prefix"): 1246 prefixes.append(sys.real_prefix) 1247 if hasattr(sys, "base_prefix"): 1248 prefixes.append(sys.base_prefix) 1249 prefixes = list(map(os.path.expanduser, prefixes)) 1250 prefixes = list(map(os.path.abspath, prefixes)) 1251 # Check longer prefixes first so we don't split in the middle of a filename 1252 prefixes = sorted(prefixes, key=len, reverse=True) 1253 filename = os.path.abspath(filename) 1254 # On Windows, make sure drive letter is uppercase 1255 if IS_WIN and filename[0] in "abcdefghijklmnopqrstuvwxyz": 1256 filename = filename[0].upper() + filename[1:] 1257 for i, prefix in enumerate(prefixes): 1258 if IS_WIN and prefix[0] in "abcdefghijklmnopqrstuvwxyz": 1259 prefixes[i] = prefix[0].upper() + prefix[1:] 1260 for src_prefix in prefixes: 1261 if filename.startswith(src_prefix): 1262 _, relative_path = filename.split(src_prefix, 1) 1263 if src_prefix != os.sep: # sys.prefix == "/" 1264 assert relative_path[0] == os.sep 1265 relative_path = relative_path[1:] 1266 return join(dst_prefix, relative_path) 1267 assert False, "Filename {} does not start with any of these prefixes: {}".format(filename, prefixes) 1268 1269 1270def find_module_filename(modname): 1271 1272 if sys.version_info < (3, 4): 1273 # noinspection PyDeprecation 1274 import imp 1275 1276 try: 1277 file_handler, filepath, _ = imp.find_module(modname) 1278 except ImportError: 1279 return None 1280 else: 1281 if file_handler is not None: 1282 file_handler.close() 1283 return filepath 1284 else: 1285 import importlib.util 1286 1287 if sys.version_info < (3, 5): 1288 1289 def find_spec(modname): 1290 # noinspection PyDeprecation 1291 loader = importlib.find_loader(modname) 1292 if loader is None: 1293 return None 1294 else: 1295 return importlib.util.spec_from_loader(modname, loader) 1296 1297 else: 1298 find_spec = importlib.util.find_spec 1299 1300 spec = find_spec(modname) 1301 if spec is None: 1302 return None 1303 if not os.path.exists(spec.origin): 1304 # https://bitbucket.org/pypy/pypy/issues/2944/origin-for-several-builtin-modules 1305 # on pypy3, some builtin modules have a bogus build-time file path, ignore them 1306 return None 1307 filepath = spec.origin 1308 # https://www.python.org/dev/peps/pep-3147/#file guarantee to be non-cached 1309 if os.path.basename(filepath) == "__init__.py": 1310 filepath = os.path.dirname(filepath) 1311 return filepath 1312 1313 1314def copy_required_modules(dst_prefix, symlink): 1315 for modname in REQUIRED_MODULES: 1316 if modname in sys.builtin_module_names: 1317 logger.info("Ignoring built-in bootstrap module: %s" % modname) 1318 continue 1319 filename = find_module_filename(modname) 1320 if filename is None: 1321 logger.info("Cannot import bootstrap module: %s" % modname) 1322 else: 1323 # special-case custom readline.so on OS X, but not for pypy: 1324 if ( 1325 modname == "readline" 1326 and IS_DARWIN 1327 and not (IS_PYPY or filename.endswith(join("lib-dynload", "readline.so"))) 1328 ): 1329 dst_filename = join(dst_prefix, "lib", PY_VERSION, "readline.so") 1330 elif modname == "readline" and IS_WIN: 1331 # special-case for Windows, where readline is not a standard module, though it may have been installed 1332 # in site-packages by a third-party package 1333 dst_filename = None 1334 else: 1335 dst_filename = change_prefix(filename, dst_prefix) 1336 if dst_filename is not None: 1337 copyfile(filename, dst_filename, symlink) 1338 if filename.endswith(".pyc"): 1339 py_file = filename[:-1] 1340 if os.path.exists(py_file): 1341 copyfile(py_file, dst_filename[:-1], symlink) 1342 1343 1344def copy_required_files(src_dir, lib_dir, symlink): 1345 if not os.path.isdir(src_dir): 1346 return 1347 for fn in os.listdir(src_dir): 1348 bn = os.path.splitext(fn)[0] 1349 if fn != "site-packages" and bn in REQUIRED_FILES: 1350 copyfile(join(src_dir, fn), join(lib_dir, fn), symlink) 1351 1352 1353def copy_license(prefix, dst_prefix, lib_dir, symlink): 1354 """Copy the license file so `license()` builtin works""" 1355 lib64_dir = lib_dir.replace("lib", "lib64") 1356 for license_path in ( 1357 # posix cpython 1358 os.path.join(prefix, os.path.relpath(lib_dir, dst_prefix), "LICENSE.txt"), 1359 # posix cpython installed in /usr/lib64 1360 os.path.join(prefix, os.path.relpath(lib64_dir, dst_prefix), "LICENSE.txt"), 1361 # windows cpython 1362 os.path.join(prefix, "LICENSE.txt"), 1363 # pypy 1364 os.path.join(prefix, "LICENSE"), 1365 ): 1366 if os.path.exists(license_path): 1367 dest = subst_path(license_path, prefix, dst_prefix) 1368 copyfile(license_path, dest, symlink) 1369 return 1370 logger.warn("No LICENSE.txt / LICENSE found in source") 1371 1372 1373def copy_include_dir(include_src, include_dest, symlink): 1374 """Copy headers from *include_src* to *include_dest* symlinking if required""" 1375 if not os.path.isdir(include_src): 1376 return 1377 # PyPy headers are located in ``pypy-dir/include`` and following code 1378 # avoids making ``venv-dir/include`` symlink to it 1379 if IS_PYPY: 1380 for fn in os.listdir(include_src): 1381 copyfile(join(include_src, fn), join(include_dest, fn), symlink) 1382 else: 1383 copyfile(include_src, include_dest, symlink) 1384 1385 1386def copy_tcltk(src, dest, symlink): 1387 """ copy tcl/tk libraries on Windows (issue #93) """ 1388 for lib_version in "8.5", "8.6": 1389 for libname in "tcl", "tk": 1390 src_dir = join(src, "tcl", libname + lib_version) 1391 dest_dir = join(dest, "tcl", libname + lib_version) 1392 # Only copy the dirs from the above combinations that exist 1393 if os.path.exists(src_dir) and not os.path.exists(dest_dir): 1394 copy_file_or_folder(src_dir, dest_dir, symlink) 1395 1396 1397def subst_path(prefix_path, prefix, home_dir): 1398 prefix_path = os.path.normpath(prefix_path) 1399 prefix = os.path.normpath(prefix) 1400 home_dir = os.path.normpath(home_dir) 1401 if not prefix_path.startswith(prefix): 1402 logger.warn("Path not in prefix %r %r", prefix_path, prefix) 1403 return 1404 return prefix_path.replace(prefix, home_dir, 1) 1405 1406 1407def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, symlink=True): 1408 """Install just the base environment, no distutils patches etc""" 1409 if sys.executable.startswith(bin_dir): 1410 print("Please use the *system* python to run this script") 1411 return 1412 1413 if clear: 1414 rm_tree(lib_dir) 1415 # FIXME: why not delete it? 1416 # Maybe it should delete everything with #!/path/to/venv/python in it 1417 logger.notify("Not deleting %s", bin_dir) 1418 1419 if hasattr(sys, "real_prefix"): 1420 logger.notify("Using real prefix %r", sys.real_prefix) 1421 prefix = sys.real_prefix 1422 elif hasattr(sys, "base_prefix"): 1423 logger.notify("Using base prefix %r", sys.base_prefix) 1424 prefix = sys.base_prefix 1425 else: 1426 prefix = sys.prefix 1427 prefix = os.path.abspath(prefix) 1428 mkdir(lib_dir) 1429 fix_lib64(lib_dir, symlink) 1430 stdlib_dirs = [os.path.dirname(os.__file__)] 1431 if IS_WIN: 1432 stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), "DLLs")) 1433 elif IS_DARWIN: 1434 stdlib_dirs.append(join(stdlib_dirs[0], "site-packages")) 1435 if hasattr(os, "symlink"): 1436 logger.info("Symlinking Python bootstrap modules") 1437 else: 1438 logger.info("Copying Python bootstrap modules") 1439 logger.indent += 2 1440 try: 1441 # copy required files... 1442 for stdlib_dir in stdlib_dirs: 1443 copy_required_files(stdlib_dir, lib_dir, symlink) 1444 # ...and modules 1445 copy_required_modules(home_dir, symlink) 1446 copy_license(prefix, home_dir, lib_dir, symlink) 1447 finally: 1448 logger.indent -= 2 1449 # ...copy tcl/tk 1450 if IS_WIN: 1451 copy_tcltk(prefix, home_dir, symlink) 1452 mkdir(join(lib_dir, "site-packages")) 1453 import site 1454 1455 site_filename = site.__file__ 1456 if site_filename.endswith(".pyc") or site_filename.endswith(".pyo"): 1457 site_filename = site_filename[:-1] 1458 elif site_filename.endswith("$py.class"): 1459 site_filename = site_filename.replace("$py.class", ".py") 1460 site_filename_dst = change_prefix(site_filename, home_dir) 1461 site_dir = os.path.dirname(site_filename_dst) 1462 writefile(site_filename_dst, SITE_PY) 1463 writefile(join(site_dir, "orig-prefix.txt"), prefix) 1464 site_packages_filename = join(site_dir, "no-global-site-packages.txt") 1465 if not site_packages: 1466 writefile(site_packages_filename, "") 1467 1468 if IS_PYPY or IS_WIN: 1469 standard_lib_include_dir = join(prefix, "include") 1470 else: 1471 standard_lib_include_dir = join(prefix, "include", PY_VERSION + ABI_FLAGS) 1472 if os.path.exists(standard_lib_include_dir): 1473 copy_include_dir(standard_lib_include_dir, inc_dir, symlink) 1474 else: 1475 logger.debug("No include dir %s", standard_lib_include_dir) 1476 1477 platform_include_dir = distutils.sysconfig.get_python_inc(plat_specific=1) 1478 if platform_include_dir != standard_lib_include_dir: 1479 platform_include_dest = distutils.sysconfig.get_python_inc(plat_specific=1, prefix=home_dir) 1480 if platform_include_dir == platform_include_dest: 1481 # Do platinc_dest manually due to a CPython bug; 1482 # not http://bugs.python.org/issue3386 but a close cousin 1483 platform_include_dest = subst_path(platform_include_dir, prefix, home_dir) 1484 if platform_include_dest: 1485 # PyPy's stdinc_dir and prefix are relative to the original binary 1486 # (traversing virtualenvs), whereas the platinc_dir is relative to 1487 # the inner virtualenv and ignores the prefix argument. 1488 # This seems more evolved than designed. 1489 copy_include_dir(platform_include_dir, platform_include_dest, symlink) 1490 1491 # pypy never uses exec_prefix, just ignore it 1492 if os.path.realpath(sys.exec_prefix) != os.path.realpath(prefix) and not IS_PYPY: 1493 if IS_WIN: 1494 exec_dir = join(sys.exec_prefix, "lib") 1495 else: 1496 exec_dir = join(sys.exec_prefix, "lib", PY_VERSION) 1497 copy_required_files(exec_dir, lib_dir, symlink) 1498 1499 mkdir(bin_dir) 1500 py_executable = join(bin_dir, os.path.basename(sys.executable)) 1501 if "Python.framework" in prefix: 1502 # OS X framework builds cause validation to break 1503 # https://github.com/pypa/virtualenv/issues/322 1504 if os.environ.get("__PYVENV_LAUNCHER__"): 1505 del os.environ["__PYVENV_LAUNCHER__"] 1506 if re.search(r"/Python(?:-32|-64)*$", py_executable): 1507 # The name of the python executable is not quite what 1508 # we want, rename it. 1509 py_executable = os.path.join(os.path.dirname(py_executable), "python") 1510 1511 logger.notify("New %s executable in %s", EXPECTED_EXE, py_executable) 1512 pc_build_dir = os.path.dirname(sys.executable) 1513 pyd_pth = os.path.join(lib_dir, "site-packages", "virtualenv_builddir_pyd.pth") 1514 if IS_WIN and os.path.exists(os.path.join(pc_build_dir, "build.bat")): 1515 logger.notify("Detected python running from build directory %s", pc_build_dir) 1516 logger.notify("Writing .pth file linking to build directory for *.pyd files") 1517 writefile(pyd_pth, pc_build_dir) 1518 else: 1519 if os.path.exists(pyd_pth): 1520 logger.info("Deleting %s (not Windows env or not build directory python)", pyd_pth) 1521 os.unlink(pyd_pth) 1522 1523 if sys.executable != py_executable: 1524 # FIXME: could I just hard link? 1525 executable = sys.executable 1526 shutil.copyfile(executable, py_executable) 1527 make_exe(py_executable) 1528 if IS_WIN or IS_CYGWIN: 1529 python_w = os.path.join(os.path.dirname(sys.executable), "pythonw.exe") 1530 if os.path.exists(python_w): 1531 logger.info("Also created pythonw.exe") 1532 shutil.copyfile(python_w, os.path.join(os.path.dirname(py_executable), "pythonw.exe")) 1533 python_d = os.path.join(os.path.dirname(sys.executable), "python_d.exe") 1534 python_d_dest = os.path.join(os.path.dirname(py_executable), "python_d.exe") 1535 if os.path.exists(python_d): 1536 logger.info("Also created python_d.exe") 1537 shutil.copyfile(python_d, python_d_dest) 1538 elif os.path.exists(python_d_dest): 1539 logger.info("Removed python_d.exe as it is no longer at the source") 1540 os.unlink(python_d_dest) 1541 1542 # we need to copy the DLL to enforce that windows will load the correct one. 1543 # may not exist if we are cygwin. 1544 if IS_PYPY: 1545 py_executable_dll_s = [("libpypy-c.dll", "libpypy_d-c.dll")] 1546 else: 1547 py_executable_dll_s = [ 1548 ("python{}.dll".format(sys.version_info[0]), "python{}_d.dll".format(sys.version_info[0])), 1549 ( 1550 "python{}{}.dll".format(sys.version_info[0], sys.version_info[1]), 1551 "python{}{}_d.dll".format(sys.version_info[0], sys.version_info[1]), 1552 ), 1553 ] 1554 1555 for py_executable_dll, py_executable_dll_d in py_executable_dll_s: 1556 python_dll = os.path.join(os.path.dirname(sys.executable), py_executable_dll) 1557 python_dll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d) 1558 python_dll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d) 1559 if os.path.exists(python_dll): 1560 logger.info("Also created %s", py_executable_dll) 1561 shutil.copyfile(python_dll, os.path.join(os.path.dirname(py_executable), py_executable_dll)) 1562 if os.path.exists(python_dll_d): 1563 logger.info("Also created %s", py_executable_dll_d) 1564 shutil.copyfile(python_dll_d, python_dll_d_dest) 1565 elif os.path.exists(python_dll_d_dest): 1566 logger.info("Removed %s as the source does not exist", python_dll_d_dest) 1567 os.unlink(python_dll_d_dest) 1568 if IS_PYPY: 1569 # make a symlink python --> pypy-c 1570 python_executable = os.path.join(os.path.dirname(py_executable), "python") 1571 if IS_WIN or IS_CYGWIN: 1572 python_executable += ".exe" 1573 logger.info("Also created executable %s", python_executable) 1574 copyfile(py_executable, python_executable, symlink) 1575 1576 if IS_WIN: 1577 for name in ["libexpat.dll", "libeay32.dll", "ssleay32.dll", "sqlite3.dll", "tcl85.dll", "tk85.dll"]: 1578 src = join(prefix, name) 1579 if os.path.exists(src): 1580 copyfile(src, join(bin_dir, name), symlink) 1581 1582 for d in sys.path: 1583 if d.endswith("lib_pypy"): 1584 break 1585 else: 1586 logger.fatal("Could not find lib_pypy in sys.path") 1587 raise SystemExit(3) 1588 logger.info("Copying lib_pypy") 1589 copyfile(d, os.path.join(home_dir, "lib_pypy"), symlink) 1590 1591 if os.path.splitext(os.path.basename(py_executable))[0] != EXPECTED_EXE: 1592 secondary_exe = os.path.join(os.path.dirname(py_executable), EXPECTED_EXE) 1593 py_executable_ext = os.path.splitext(py_executable)[1] 1594 if py_executable_ext.lower() == ".exe": 1595 # python2.4 gives an extension of '.4' :P 1596 secondary_exe += py_executable_ext 1597 if os.path.exists(secondary_exe): 1598 logger.warn( 1599 "Not overwriting existing {} script {} (you must use {})".format( 1600 EXPECTED_EXE, secondary_exe, py_executable 1601 ) 1602 ) 1603 else: 1604 logger.notify("Also creating executable in %s", secondary_exe) 1605 shutil.copyfile(sys.executable, secondary_exe) 1606 make_exe(secondary_exe) 1607 1608 if ".framework" in prefix: 1609 original_python = None 1610 if "Python.framework" in prefix: 1611 logger.debug("MacOSX Python framework detected") 1612 # Make sure we use the embedded interpreter inside 1613 # the framework, even if sys.executable points to 1614 # the stub executable in ${sys.prefix}/bin 1615 # See http://groups.google.com/group/python-virtualenv/ 1616 # browse_thread/thread/17cab2f85da75951 1617 original_python = os.path.join(prefix, "Resources/Python.app/Contents/MacOS/Python") 1618 if "EPD" in prefix: 1619 logger.debug("EPD framework detected") 1620 original_python = os.path.join(prefix, "bin/python") 1621 shutil.copy(original_python, py_executable) 1622 1623 # Copy the framework's dylib into the virtual 1624 # environment 1625 virtual_lib = os.path.join(home_dir, ".Python") 1626 1627 if os.path.exists(virtual_lib): 1628 os.unlink(virtual_lib) 1629 copyfile(os.path.join(prefix, "Python"), virtual_lib, symlink) 1630 1631 # And then change the install_name of the copied python executable 1632 # noinspection PyBroadException 1633 try: 1634 mach_o_change(py_executable, os.path.join(prefix, "Python"), "@executable_path/../.Python") 1635 except Exception: 1636 e = sys.exc_info()[1] 1637 logger.warn("Could not call mach_o_change: %s. " "Trying to call install_name_tool instead.", e) 1638 try: 1639 call_subprocess( 1640 [ 1641 "install_name_tool", 1642 "-change", 1643 os.path.join(prefix, "Python"), 1644 "@executable_path/../.Python", 1645 py_executable, 1646 ] 1647 ) 1648 except Exception: 1649 logger.fatal("Could not call install_name_tool -- you must " "have Apple's development tools installed") 1650 raise 1651 1652 if not IS_WIN: 1653 # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist 1654 py_exe_version_major = "python{}".format(sys.version_info[0]) 1655 py_exe_version_major_minor = "python{}.{}".format(sys.version_info[0], sys.version_info[1]) 1656 py_exe_no_version = "python" 1657 required_symlinks = [py_exe_no_version, py_exe_version_major, py_exe_version_major_minor] 1658 1659 py_executable_base = os.path.basename(py_executable) 1660 1661 if py_executable_base in required_symlinks: 1662 # Don't try to symlink to yourself. 1663 required_symlinks.remove(py_executable_base) 1664 1665 for pth in required_symlinks: 1666 full_pth = join(bin_dir, pth) 1667 if os.path.exists(full_pth): 1668 os.unlink(full_pth) 1669 if symlink: 1670 os.symlink(py_executable_base, full_pth) 1671 else: 1672 copyfile(py_executable, full_pth, symlink) 1673 1674 cmd = [ 1675 py_executable, 1676 "-c", 1677 "import sys;out=sys.stdout;" 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))', 1678 ] 1679 logger.info('Testing executable with %s %s "%s"', *cmd) 1680 try: 1681 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) 1682 proc_stdout, proc_stderr = proc.communicate() 1683 except OSError: 1684 e = sys.exc_info()[1] 1685 if e.errno == errno.EACCES: 1686 logger.fatal("ERROR: The executable {} could not be run: {}".format(py_executable, e)) 1687 sys.exit(100) 1688 else: 1689 raise e 1690 1691 proc_stdout = proc_stdout.strip().decode("utf-8") 1692 # normalize paths using realpath to ensure that a virtualenv correctly identifies itself even 1693 # when addressed over a symlink 1694 proc_stdout = os.path.normcase(os.path.realpath(proc_stdout)) 1695 norm_home_dir = os.path.normcase(os.path.realpath(home_dir)) 1696 if hasattr(norm_home_dir, "decode"): 1697 norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding()) 1698 if proc_stdout != norm_home_dir: 1699 logger.fatal("ERROR: The executable %s is not functioning", py_executable) 1700 logger.fatal("ERROR: It thinks sys.prefix is {!r} (should be {!r})".format(proc_stdout, norm_home_dir)) 1701 logger.fatal("ERROR: virtualenv is not compatible with this system or executable") 1702 if IS_WIN: 1703 logger.fatal( 1704 "Note: some Windows users have reported this error when they " 1705 'installed Python for "Only this user" or have multiple ' 1706 "versions of Python installed. Copying the appropriate " 1707 "PythonXX.dll to the virtualenv Scripts/ directory may fix " 1708 "this problem." 1709 ) 1710 sys.exit(100) 1711 else: 1712 logger.info("Got sys.prefix result: %r", proc_stdout) 1713 1714 pydistutils = os.path.expanduser("~/.pydistutils.cfg") 1715 if os.path.exists(pydistutils): 1716 logger.notify("Please make sure you remove any previous custom paths from " "your %s file.", pydistutils) 1717 # FIXME: really this should be calculated earlier 1718 1719 fix_local_scheme(home_dir, symlink) 1720 1721 if site_packages: 1722 if os.path.exists(site_packages_filename): 1723 logger.info("Deleting %s", site_packages_filename) 1724 os.unlink(site_packages_filename) 1725 1726 return py_executable 1727 1728 1729def install_activate(home_dir, bin_dir, prompt=None): 1730 if IS_WIN: 1731 files = {"activate.bat": ACTIVATE_BAT, "deactivate.bat": DEACTIVATE_BAT, "activate.ps1": ACTIVATE_PS} 1732 1733 # MSYS needs paths of the form /c/path/to/file 1734 drive, tail = os.path.splitdrive(home_dir.replace(os.sep, "/")) 1735 home_dir_msys = (drive and "/{}{}" or "{}{}").format(drive[:1], tail) 1736 1737 # Run-time conditional enables (basic) Cygwin compatibility 1738 home_dir_sh = """$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '{}'; else echo '{}'; fi;)""".format( 1739 home_dir, home_dir_msys 1740 ) 1741 files["activate"] = ACTIVATE_SH.replace("__VIRTUAL_ENV__", home_dir_sh) 1742 1743 else: 1744 files = { 1745 "activate": ACTIVATE_SH, 1746 "activate.fish": ACTIVATE_FISH, 1747 "activate.csh": ACTIVATE_CSH, 1748 "activate.ps1": ACTIVATE_PS, 1749 } 1750 files["activate_this.py"] = ACTIVATE_THIS 1751 1752 if sys.version_info >= (3, 4): 1753 # Add xonsh support 1754 files["activate.xsh"] = ACTIVATE_XSH 1755 1756 install_files(home_dir, bin_dir, prompt, files) 1757 1758 1759def install_files(home_dir, bin_dir, prompt, files): 1760 if hasattr(home_dir, "decode"): 1761 home_dir = home_dir.decode(sys.getfilesystemencoding()) 1762 virtualenv_name = os.path.basename(home_dir) 1763 for name, content in files.items(): 1764 content = content.replace("__VIRTUAL_PROMPT__", prompt or "") 1765 content = content.replace("__VIRTUAL_WINPROMPT__", prompt or "({}) ".format(virtualenv_name)) 1766 content = content.replace("__VIRTUAL_ENV__", home_dir) 1767 content = content.replace("__VIRTUAL_NAME__", virtualenv_name) 1768 content = content.replace("__BIN_NAME__", os.path.basename(bin_dir)) 1769 content = content.replace("__PATH_SEP__", os.pathsep) 1770 writefile(os.path.join(bin_dir, name), content) 1771 1772 1773def install_python_config(home_dir, bin_dir, prompt=None): 1774 if IS_WIN: 1775 files = {} 1776 else: 1777 files = {"python-config": PYTHON_CONFIG} 1778 install_files(home_dir, bin_dir, prompt, files) 1779 for name, _ in files.items(): 1780 make_exe(os.path.join(bin_dir, name)) 1781 1782 1783def install_distutils(home_dir): 1784 distutils_path = change_prefix(distutils.__path__[0], home_dir) 1785 mkdir(distutils_path) 1786 # FIXME: maybe this prefix setting should only be put in place if 1787 # there's a local distutils.cfg with a prefix setting? 1788 # FIXME: this is breaking things, removing for now: 1789 # distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" home_dir 1790 writefile(os.path.join(distutils_path, "__init__.py"), DISTUTILS_INIT) 1791 writefile(os.path.join(distutils_path, "distutils.cfg"), DISTUTILS_CFG, overwrite=False) 1792 1793 1794def fix_local_scheme(home_dir, symlink=True): 1795 """ 1796 Platforms that use the "posix_local" install scheme (like Ubuntu with 1797 Python 2.7) need to be given an additional "local" location, sigh. 1798 """ 1799 try: 1800 import sysconfig 1801 except ImportError: 1802 pass 1803 else: 1804 # noinspection PyProtectedMember 1805 if sysconfig._get_default_scheme() == "posix_local": 1806 local_path = os.path.join(home_dir, "local") 1807 if not os.path.exists(local_path): 1808 os.mkdir(local_path) 1809 for subdir_name in os.listdir(home_dir): 1810 if subdir_name == "local": 1811 continue 1812 copyfile( 1813 os.path.abspath(os.path.join(home_dir, subdir_name)), 1814 os.path.join(local_path, subdir_name), 1815 symlink, 1816 ) 1817 1818 1819def fix_lib64(lib_dir, symlink=True): 1820 """ 1821 Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y 1822 instead of lib/pythonX.Y. If this is such a platform we'll just create a 1823 symlink so lib64 points to lib 1824 """ 1825 # PyPy's library path scheme is not affected by this. 1826 # Return early or we will die on the following assert. 1827 if IS_PYPY: 1828 logger.debug("PyPy detected, skipping lib64 symlinking") 1829 return 1830 # Check we have a lib64 library path 1831 if not [p for p in distutils.sysconfig.get_config_vars().values() if isinstance(p, basestring) and "lib64" in p]: 1832 return 1833 1834 logger.debug("This system uses lib64; symlinking lib64 to lib") 1835 1836 assert os.path.basename(lib_dir) == PY_VERSION, "Unexpected python lib dir: {!r}".format(lib_dir) 1837 lib_parent = os.path.dirname(lib_dir) 1838 top_level = os.path.dirname(lib_parent) 1839 lib_dir = os.path.join(top_level, "lib") 1840 lib64_link = os.path.join(top_level, "lib64") 1841 assert os.path.basename(lib_parent) == "lib", "Unexpected parent dir: {!r}".format(lib_parent) 1842 if os.path.lexists(lib64_link): 1843 return 1844 if symlink: 1845 os.symlink("lib", lib64_link) 1846 else: 1847 copyfile(lib_dir, lib64_link, symlink=False) 1848 1849 1850def resolve_interpreter(exe): 1851 """ 1852 If the executable given isn't an absolute path, search $PATH for the interpreter 1853 """ 1854 # If the "executable" is a version number, get the installed executable for 1855 # that version 1856 orig_exe = exe 1857 python_versions = get_installed_pythons() 1858 if exe in python_versions: 1859 exe = python_versions[exe] 1860 1861 if os.path.abspath(exe) != exe: 1862 exe = distutils.spawn.find_executable(exe) or exe 1863 if not os.path.exists(exe): 1864 logger.fatal("The path {} (from --python={}) does not exist".format(exe, orig_exe)) 1865 raise SystemExit(3) 1866 if not is_executable(exe): 1867 logger.fatal("The path {} (from --python={}) is not an executable file".format(exe, orig_exe)) 1868 raise SystemExit(3) 1869 return exe 1870 1871 1872def is_executable(exe): 1873 """Checks a file is executable""" 1874 return os.path.isfile(exe) and os.access(exe, os.X_OK) 1875 1876 1877# Relocating the environment: 1878def make_environment_relocatable(home_dir): 1879 """ 1880 Makes the already-existing environment use relative paths, and takes out 1881 the #!-based environment selection in scripts. 1882 """ 1883 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 1884 activate_this = os.path.join(bin_dir, "activate_this.py") 1885 if not os.path.exists(activate_this): 1886 logger.fatal( 1887 "The environment doesn't have a file %s -- please re-run virtualenv " "on this environment to update it", 1888 activate_this, 1889 ) 1890 fixup_scripts(home_dir, bin_dir) 1891 fixup_pth_and_egg_link(home_dir) 1892 # FIXME: need to fix up distutils.cfg 1893 1894 1895OK_ABS_SCRIPTS = [ 1896 "python", 1897 PY_VERSION, 1898 "activate", 1899 "activate.bat", 1900 "activate_this.py", 1901 "activate.fish", 1902 "activate.csh", 1903 "activate.xsh", 1904] 1905 1906 1907def fixup_scripts(_, bin_dir): 1908 if IS_WIN: 1909 new_shebang_args = ("{} /c".format(os.path.normcase(os.environ.get("COMSPEC", "cmd.exe"))), "", ".exe") 1910 else: 1911 new_shebang_args = ("/usr/bin/env", VERSION, "") 1912 1913 # This is what we expect at the top of scripts: 1914 shebang = "#!{}".format( 1915 os.path.normcase(os.path.join(os.path.abspath(bin_dir), "python{}".format(new_shebang_args[2]))) 1916 ) 1917 # This is what we'll put: 1918 new_shebang = "#!{} python{}{}".format(*new_shebang_args) 1919 1920 for filename in os.listdir(bin_dir): 1921 filename = os.path.join(bin_dir, filename) 1922 if not os.path.isfile(filename): 1923 # ignore child directories, e.g. .svn ones. 1924 continue 1925 with open(filename, "rb") as f: 1926 try: 1927 lines = f.read().decode("utf-8").splitlines() 1928 except UnicodeDecodeError: 1929 # This is probably a binary program instead 1930 # of a script, so just ignore it. 1931 continue 1932 if not lines: 1933 logger.warn("Script %s is an empty file", filename) 1934 continue 1935 1936 old_shebang = lines[0].strip() 1937 old_shebang = old_shebang[0:2] + os.path.normcase(old_shebang[2:]) 1938 1939 if not old_shebang.startswith(shebang): 1940 if os.path.basename(filename) in OK_ABS_SCRIPTS: 1941 logger.debug("Cannot make script %s relative", filename) 1942 elif lines[0].strip() == new_shebang: 1943 logger.info("Script %s has already been made relative", filename) 1944 else: 1945 logger.warn( 1946 "Script %s cannot be made relative (it's not a normal script that starts with %s)", 1947 filename, 1948 shebang, 1949 ) 1950 continue 1951 logger.notify("Making script %s relative", filename) 1952 script = relative_script([new_shebang] + lines[1:]) 1953 with open(filename, "wb") as f: 1954 f.write("\n".join(script).encode("utf-8")) 1955 1956 1957def relative_script(lines): 1958 """Return a script that'll work in a relocatable environment.""" 1959 activate = ( 1960 "import os; " 1961 "activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); " 1962 "exec(compile(open(activate_this).read(), activate_this, 'exec'), { '__file__': activate_this}); " 1963 "del os, activate_this" 1964 ) 1965 # Find the last future statement in the script. If we insert the activation 1966 # line before a future statement, Python will raise a SyntaxError. 1967 activate_at = None 1968 for idx, line in reversed(list(enumerate(lines))): 1969 if line.split()[:3] == ["from", "__future__", "import"]: 1970 activate_at = idx + 1 1971 break 1972 if activate_at is None: 1973 # Activate after the shebang. 1974 activate_at = 1 1975 return lines[:activate_at] + ["", activate, ""] + lines[activate_at:] 1976 1977 1978def fixup_pth_and_egg_link(home_dir, sys_path=None): 1979 """Makes .pth and .egg-link files use relative paths""" 1980 home_dir = os.path.normcase(os.path.abspath(home_dir)) 1981 if sys_path is None: 1982 sys_path = sys.path 1983 for a_path in sys_path: 1984 if not a_path: 1985 a_path = "." 1986 if not os.path.isdir(a_path): 1987 continue 1988 a_path = os.path.normcase(os.path.abspath(a_path)) 1989 if not a_path.startswith(home_dir): 1990 logger.debug("Skipping system (non-environment) directory %s", a_path) 1991 continue 1992 for filename in os.listdir(a_path): 1993 filename = os.path.join(a_path, filename) 1994 if filename.endswith(".pth"): 1995 if not os.access(filename, os.W_OK): 1996 logger.warn("Cannot write .pth file %s, skipping", filename) 1997 else: 1998 fixup_pth_file(filename) 1999 if filename.endswith(".egg-link"): 2000 if not os.access(filename, os.W_OK): 2001 logger.warn("Cannot write .egg-link file %s, skipping", filename) 2002 else: 2003 fixup_egg_link(filename) 2004 2005 2006def fixup_pth_file(filename): 2007 lines = [] 2008 with open(filename) as f: 2009 prev_lines = f.readlines() 2010 for line in prev_lines: 2011 line = line.strip() 2012 if not line or line.startswith("#") or line.startswith("import ") or os.path.abspath(line) != line: 2013 lines.append(line) 2014 else: 2015 new_value = make_relative_path(filename, line) 2016 if line != new_value: 2017 logger.debug("Rewriting path {} as {} (in {})".format(line, new_value, filename)) 2018 lines.append(new_value) 2019 if lines == prev_lines: 2020 logger.info("No changes to .pth file %s", filename) 2021 return 2022 logger.notify("Making paths in .pth file %s relative", filename) 2023 with open(filename, "w") as f: 2024 f.write("\n".join(lines) + "\n") 2025 2026 2027def fixup_egg_link(filename): 2028 with open(filename) as f: 2029 link = f.readline().strip() 2030 if os.path.abspath(link) != link: 2031 logger.debug("Link in %s already relative", filename) 2032 return 2033 new_link = make_relative_path(filename, link) 2034 logger.notify("Rewriting link {} in {} as {}".format(link, filename, new_link)) 2035 with open(filename, "w") as f: 2036 f.write(new_link) 2037 2038 2039def make_relative_path(source, dest, dest_is_directory=True): 2040 """ 2041 Make a filename relative, where the filename is dest, and it is 2042 being referred to from the filename source. 2043 2044 >>> make_relative_path('/usr/share/something/a-file.pth', 2045 ... '/usr/share/another-place/src/Directory') 2046 '../another-place/src/Directory' 2047 >>> make_relative_path('/usr/share/something/a-file.pth', 2048 ... '/home/user/src/Directory') 2049 '../../../home/user/src/Directory' 2050 >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/') 2051 './' 2052 """ 2053 source = os.path.dirname(source) 2054 if not dest_is_directory: 2055 dest_filename = os.path.basename(dest) 2056 dest = os.path.dirname(dest) 2057 else: 2058 dest_filename = None 2059 dest = os.path.normpath(os.path.abspath(dest)) 2060 source = os.path.normpath(os.path.abspath(source)) 2061 dest_parts = dest.strip(os.path.sep).split(os.path.sep) 2062 source_parts = source.strip(os.path.sep).split(os.path.sep) 2063 while dest_parts and source_parts and dest_parts[0] == source_parts[0]: 2064 dest_parts.pop(0) 2065 source_parts.pop(0) 2066 full_parts = [".."] * len(source_parts) + dest_parts 2067 if not dest_is_directory and dest_filename is not None: 2068 full_parts.append(dest_filename) 2069 if not full_parts: 2070 # Special case for the current directory (otherwise it'd be '') 2071 return "./" 2072 return os.path.sep.join(full_parts) 2073 2074 2075FILE_PATH = __file__ if os.path.isabs(__file__) else os.path.join(os.getcwd(), __file__) 2076 2077 2078# Bootstrap script creation: 2079def create_bootstrap_script(extra_text, python_version=""): 2080 """ 2081 Creates a bootstrap script, which is like this script but with 2082 extend_parser, adjust_options, and after_install hooks. 2083 2084 This returns a string that (written to disk of course) can be used 2085 as a bootstrap script with your own customizations. The script 2086 will be the standard virtualenv.py script, with your extra text 2087 added (your extra text should be Python code). 2088 2089 If you include these functions, they will be called: 2090 2091 ``extend_parser(optparse_parser)``: 2092 You can add or remove options from the parser here. 2093 2094 ``adjust_options(options, args)``: 2095 You can change options here, or change the args (if you accept 2096 different kinds of arguments, be sure you modify ``args`` so it is 2097 only ``[DEST_DIR]``). 2098 2099 ``after_install(options, home_dir)``: 2100 2101 After everything is installed, this function is called. This 2102 is probably the function you are most likely to use. An 2103 example would be:: 2104 2105 def after_install(options, home_dir): 2106 subprocess.call([join(home_dir, 'bin', 'easy_install'), 2107 'MyPackage']) 2108 subprocess.call([join(home_dir, 'bin', 'my-package-script'), 2109 'setup', home_dir]) 2110 2111 This example immediately installs a package, and runs a setup 2112 script from that package. 2113 2114 If you provide something like ``python_version='2.5'`` then the 2115 script will start with ``#!/usr/bin/env python2.5`` instead of 2116 ``#!/usr/bin/env python``. You can use this when the script must 2117 be run with a particular Python version. 2118 """ 2119 filename = FILE_PATH 2120 if filename.endswith(".pyc"): 2121 filename = filename[:-1] 2122 with codecs.open(filename, "r", encoding="utf-8") as f: 2123 content = f.read() 2124 py_exe = "python{}".format(python_version) 2125 content = "#!/usr/bin/env {}\n# WARNING: This file is generated\n{}".format(py_exe, content) 2126 # we build the string as two, to avoid replacing here, but yes further done 2127 return content.replace("# EXTEND - " "bootstrap here", extra_text) 2128 2129 2130# EXTEND - bootstrap here 2131 2132 2133def convert(s): 2134 b = base64.b64decode(s.encode("ascii")) 2135 return zlib.decompress(b).decode("utf-8") 2136 2137 2138# file site.py 2139SITE_PY = convert( 2140 """ 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 2291""" 2292) 2293 2294# file activate.sh 2295ACTIVATE_SH = convert( 2296 """ 2297eJytVW1P2zAQ/u5fcaQVG9s6VvjGVLQyKoEELWo6JjZQMMmVWEudynYK5eW/75w3kgbYh9EPbe27 2298s5977p5zCyah0DAVEcIs0QauEBKNAdwIE4Kj40T5CFdCbnLfiAU36MCHqYpncMV1+IG1YBkn4HMp 2299YwMqkSAMBEKhb6IlY0xM4Tc47fu9vnvguaMf4++DzqMDPdr74sDFVzAhSgb0QT+MwTmjw1IY+cXG 2300gtO+EnOzA+ftYtsG765vZYG3dOX2NpsKxgIsUML7DbhP7YnUaKAzhfkyiH3Y3QxwsSmTKIKt3fUu 2301S31aoNB6xVEAKBdCxXKG0sCCK8GvItS51xpl07mD9v1pf/zRe4QLijOJkhqMShAoWzIAQQ7Qj7gi 2302GrkBHkVpOFnzeCLEGx3te6eH48mP/pF30p8c7NB5xAhUKLEfa+o57Ya7U3rg7TxWJnUs97KcG0Gp 2303nXj6B5qzycFoeDA6HrwAqbQ3gJWWJrzS9CrIupctaUZ82qQ6jBMqUICG2ivtP+AygDsdfoKbUPgh 2304hHyBwOmHTH48m1mzCakGtqfyo6jBfSoJ1cbEcE0IqH3o3zRWdjHn1Hx5qP4M8JNkECcmNxshr/Nj 2305ao6WIGhbisEPubxGDTekJx7YryVYbdC11GNzQo5BUQCiXxbq6KRUPzyUm79IMaeDsXs4GnaeK0Oa 2306ZEdRF5cdXSPtlQK73Rcq63YbJXW7zVq63VeLmJsLIJlLYR0MT5/SX7PYuvlEkLEMUJOQrIRxBV4L 2307XIymUDisrQDoWFOh/eL2R0bjKbMLpTDCBa9pujIt6nczVkHbczyvsvQ8h+U8VFNiDbERk5lQ80XF 2308e9Pz9g6H3rB/PPC8ndytquMS95MgLGG0w2plfU2qLwjLwlqR6epV6SjN2jO9pZr9/qHb3zsaeCfj 23090fHJpNGYq43QsyBdW+Gnoju3T4RmxxCnsNaD2xc6suleOxQjjfWA95c0HFDyGcJ5jfhz53IDasH5 2310NKx0tk2+Bcf8D4JOFNrZkEgeCa7zF4SSEOadprmukAdLC1ghq3pUJFl9b9bXV04itdt3g7FsWT5Z 23118yUNHQmdWe7ntL85WTe/yRx8gxn4n/Pvf2bfc3OPavYXWw6XFQ== 2312""" 2313) 2314 2315# file activate.fish 2316ACTIVATE_FISH = convert( 2317 """ 2318eJytVm1v2zYQ/q5fcZUdyClqGVuHfQgwDGnjIQYSO3DcAMM6yLREWxxo0iMpty7243ekLImy5RQY 2319lg+xTd7rc3cPrweLnGlYM05hW2gDKwqFphn+Y2IDSy0LlVJYMTEiqWF7Ymi8ZjpfwtsvzORMAAFV 2320CGGF7TkMIDdmdzMa2V86p5zHqdzCNWiqNZPibRz04E6CkMYqAjOQMUVTww9xEKwLgV6kgGRFdM7W 2321h2RHTA7DDMKPUuypMhodOkfuwkjQckttIBuwKpASAWhObgT7RsMA8E9T41SOxvpEbfb1hVWqLhqh 2322P37400mspXKO8FAZwGx9mR/jeHiU67AW9psfN/3aSBkSFVn5meYSPMHAXngoWG+XUHDpnqPgwOlA 2323oXRlc4d/wCiIbiKIPovoxGVGqzpbf9H4KxZoz5QpCKdiD1uZUSAiQ+umUMK6NjnFaqot4ZgWikqx 2324pcLEkfPaQ0ELjOSZfwt7ohhZcaqdFFuDodh8Q4GwJbOHu+RlMl98un1Inm4X92ENcc81l8bu2mDz 2325FSvbWq7Rhq7T/K9M64Lq0U/vfwbCDVXY0tYW5Bg8R5xqm5XvQQnQb5Pn++RlPH+ezKYlUGEcQvhZ 2326hNfYFDDkBt7XulXZh5uvpfVBu2LnuVzXupRretnQuWajeOydWodCt7Ar7Hfg/X1xP5vezx7HYXAW 2327R313Gk198XocbbFXonGYP81nj0+LZIbYzyd3TTy22aru1DD8GxLsJQdzslNyuzNedzxjGNj5FE8P 2328wGWKLbl0E5tUFlxdlrZtCefyi2teRbdyj6JyDUvP7rLiQM87XcbtnDmcmw+8iMaKaOoNUKRPfJSz 2329pI1U1AUjFdswQXjjx3cPXXl7AukZOt/ToJfx9IvaVaJ2WY/SVfXH05d2uUPHPThDIbz5BSIhRYbH 2330qrBsQ6NWEfl6WN296Y55d8hk2n3VENiFdP2X5YKIP8R1li7THnwSNlOmFOV0T3wqiwOPPNv5BUE1 2331VR4+ECaJ9zNJQmv//2O4/8hsVaRnpILs1nqV+yWh1UR2WdFJOgBbJBf2vfRHSfJhMk2mt49jROKo 2332UuO97Dd0srQ9hYdxUH5aUjghm+5QPELrkqe+lfar2PTb7mByPBhuy7PjNuGka2L71s4suZs83354 2333GB/nJzw+jB/l7uBGPi2wmbCR2sRQ+yZIGaczeqSh1uT7Q3820y3xTk7AwSN72gqorw0xhX7n1iBP 2334R6MUsXub3nFywBXujBSt+1K5MuKT4lMZpMRNRjHcJ9DqHj+zXz2ZydquiO/gL7uU7hTdIcQuOH+L 2335EGRLG9/+w9JM1pG0kuaBc2VUTJg1RFf6Sked4jDAXJJUcsy9XG9eebsbc4MrfQ1RhzIMcHiojbjd 2336HaFntuLSEoJ5x7NQw1nr2NkOqV3T+g3qIQ54ubrXgp0032bvamC6yP4kaNfx/wIsXsYv 2337""" 2338) 2339 2340# file activate.csh 2341ACTIVATE_CSH = convert( 2342 """ 2343eJx9VNtO4zAQffdXDKEiUEFhX8t22bJFWqRyEVuQVkKy3Hi6sZQ44Dit+sK379hJittG5KGqPZdz 2344fOZyCLNUlbBQGUJelRbmCFWJElbKphCVRWUShLnS5yKxaiksDpIyjaC/MEUO9Lc/YIfwt6ggEVoX 2345FkylQVmQymBis7Wz/jJIcRLma5iIpZIIEwXXmSgVfJf+Qs5//suFygZJkf8YMFaiBY2rTGkcxa8s 2346ZkxkSpQgsWUBsUVi27viD9MJf7l9mj2Pp/xxPPsNByO4gKMjoCSol+Dvot6e3/A9cl6VdmB71ksw 2347mIoyvYROnKeHu8dZiARvpMebHe0CeccvoLz9sjY5tq3h5v6lgY5eD4b9yGFFutCSrkzlRMAm554y 2348we3bWhYJqXcIzx5bGYMZLoW2sBRGiXmG5YAFsdsIvhA7rCDiPDhyHtXl2lOQpGhkZtuVCKKH7+ec 2349X9/e8/vx3Q3nw00EfWoBxwFWrRTBeSWiE7Apagb0OXRKz7XIEUbQFcMwK7HLOT6OtwlZQo9PIGao 2350pVrULKj64Ysnt3/G19ObtgkCJrXzF74jRz2MaCnJgtcN5B7wLfK2DedOp4vGydPcet5urq2XBEZv 2351DcnQpBZVJt0KUBqEa4YzpS0a3x7odFOm0Dlqe9oEkN8qVUlK01/iKfSa3LRRKmqkBc2vBKFpmyCs 2352XG4d2yYyEQZBzIvKOgLN+JDveiVoaXyqedVYOkTrmCRqutrfNVHr6xMFBhh9QD/qNQuGLvq72d03 23533Jy2CtGCf0rca/tp+N4BXqsflKquRr0L2sjmuClOu+/8/NKvTQsNZ3l9ZqxeTew//1a6EA== 2354""" 2355) 2356 2357# file activate.xsh 2358ACTIVATE_XSH = convert( 2359 """ 2360eJyNU11PwjAUfe+vuNY9sIj7ASQ+YCSBRD6i02gIaSq7gyWjXdqyaIz/3XYwVmB+9GFZ78c57T2n 2361lNIXKfQa+NJkJTcIeqmywkAqFZSZMlueoygppSRVcgPvrjgyUuYask0hlYEVGqaxAK6B7f8JSTAF 2362lmCN2uFqpcMeAbuyFGjxkcglhUwAzzOuUe9SbiWY18H5vm5B6sbgM4qir8jSdCib3t+x59FD/NS/ 2363Z7N+PKRdoDRskAIXhBsIziqPyFrSf9O9xsPpZDgdD85JD6lz6kPqtwM0RYdx1bnB5Lka2u5cxzML 2364vKLWTjZ7mI5n8b8A9rUNjpAiQW3U1gmKFIQ0lXpW1gblEh4xT6EuvGjXtHGFE5ZcwlZotGhKYY4l 2365FwZKrjL+lqMmvoXmp4dYhKQV1M7d6yPEv5jNKcqYf1VGbcmZB5x4lRcCfzfvLXaBiCdJ5wj46uD+ 2366Tmg3luR2NGGT/nhgGbpgX48wN7HaYhcUFjlfYrULCTkxWru36jF59rJ9NlJlf7JQde5j11VS+yZr 23670d22eUPaxdycLKMTvqWjR3610emDtgTu36ylcJe83rhv/di/AYN1UZY= 2368""" 2369) 2370 2371# file activate.bat 2372ACTIVATE_BAT = convert( 2373 """ 2374eJyVk1FLhEAUhd8X/A8XWSkf28dCyMUpBR3FzAiCS+WYwq4TOdXfb0Z3dTJdyCfveO85n8frNXut 2375OPCyNFbGqmUCzDxIs3s3REJzB1GrEE3VVJdQsLJuWAEYh97QkaRxlGRwbqxAXp1Uf+RYM32W1LKB 23767Vp2nJC6DReD9m+5qeQ6Wd+a/SN7dlzn9oI7dxsSXJCcoXOskfLgYXdv/j8LnXiM8iGg/RmiZmOr 2377bFMSgcebMwGfKhgbBIfnL14X8P7BX3Zs38J3LSoQFdtD3YCVuJlvnfgmj5kfUz+OCLxxqUWoF9zk 2378qtYAFyZkBsO9ArzUh/td0ZqP9IskElTFMsnwb4/GqeoLPUlZT5dJvf8Id5hQIONynUSa2G0Wc+m8 2379Z+w2w4/Tt2hbYT0hbgOK1I0I4tUw/QOTZfLE 2380""" 2381) 2382 2383# file deactivate.bat 2384DEACTIVATE_BAT = convert( 2385 """ 2386eJyFkN0KgkAUhO8X9h0GQapXCIQEDQX/EBO6kso1F9KN3Or1201Si6JzN+fMGT5mxQ61gKgqSijp 2387mETup9nGDgo3yi29S90QjmhnEteOYb6AFNjdBC9xvoj9iTUd7lzWkDVrwFuYiZ15JiW8QiskSlbx 2388lpUo4sApXtlJGodJhqNQWW7k+Ou831ACNZrC6BeW+eXPNEbfl7OiXr6H/oHZZl4ceXHoToG0nuIM 2389pk+k4fAba/wd0Pr4P2CqyLeOlJ4iKfkJo6v/iaH9YzfPMEoeMG2RUA== 2390""" 2391) 2392 2393# file activate.ps1 2394ACTIVATE_PS = convert( 2395 """ 2396eJytVU1v4jAQvftXTNNoF9QNvSP1kG6RikQpIiyX3ZXlJkOx5NiR46RFK/77Oh+QkEBVrXYOSPZ8 2397+L2ZN8FNQ80TM149TgO68FePcAduvOMyVyEzXMlRvAtVHDMZjRJmtsStE+79YEIfpksbHySCG29h 2398vTBYYqpEjtXJcY9lb0cjZwj2WqM0hGwyGRbV4VWoFybGETJ7zpnBwc/0jZtw+xvcuZIPmBqdFS4c 2399wh8C1vgGBit7XT2RM83Zi8AxfZ490PV0ufrhz8oXD/GFuSjz8YHd5ZRj/BJjZUms60hweqEOeEGo 2400EqwJlJl7cgbggemYKhHRnGuTMUETreLEnEA8Bla+AulHuV2sU4Nx89ivSxktjGVTDpwm83UbTbto 2401Jwy8idZK+9X8Ai7sQMXuu5KGywy7j1xdmGJh1xCg2EBUe68+ptRI5OO4ZBepsIax7yutdNcgkp3Z 2402Wo8XQ3XrMv2aFknXkMkUDXCtUWDOpDkKLSUNEPCkklFDjhC33Sg7wcOWkG6zC2frSMgc3xq9nWgL 2403vDmLEXoSBBsvMmzETUhb5073yVtK76dzOvefJtRaEUaDyYJSB25aRaqpdXIth8C/n03oYvn8tFgd 2404ptht7hnVtebtOPVYTvV+Lumutw+NpBzatKFEUzDwpN1Sp62u3uC7cCoJ+lEEZosQZqlRVggaN/wd 2405jCov8Z2nVtav0Nm5koANzbnK0hozzctp3MGXTy5uYefJ3FwoPjzm7ludRJHiv/FmHbphpovPc832 2406G7xkBiIlv9pfnoZMR8DN6P83wZX41s13Bu6g/cfS2x9vhmwDwyE4pw3tF/t8N/fkLzQ3ME8= 2407""" 2408) 2409 2410# file distutils-init.py 2411DISTUTILS_INIT = convert( 2412 """ 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 2438""" 2439) 2440 2441# file distutils.cfg 2442DISTUTILS_CFG = convert( 2443 """ 2444eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH 2445xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg 24469FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q= 2447""" 2448) 2449 2450# file activate_this.py 2451ACTIVATE_THIS = convert( 2452 """ 2453eJylVE1v2zAMvetXENqh9pZ5wHYL0EMOBdqh64It7RAEhaE4TKzOlgxJ+ULR/15Sdhr341BsOcSW 24549fj4SD5JSjkqgt6ogLDRLqxVhWYDS+ugWDuHJoA2AV3jkP6HQlx7BNxhkdgGTRJK7fOlrjDNHKpF 2455kg7g/iSPX/L8ZAhP+w9pJsSEVlAoA3OEtccFbEs0sLdrqNc+8CegTdxpH7RZwXgfSmv6+QdgbCDS 2456Z1rn2nxpIjQTUkqh68a6ANYf3rwO+PS+90IEtx8KoN9BqcBdgU2AK1XjmXPWtdtOaZI08h5d0NbE 2457nURO+3r/qRWpTIX4AFQTBS64AAgWxqPJOUQaYBjQUxuvFxgLZtBCOyyCdftU0DKnJZxSnVmjQpnR 2458ypD85LBWc8/P5CAhTQVtUcO0s2YmOZu8PcZ7bLI7q00y66hv4RMcA7IVhqQNGoCUaeabSofkGEz0 2459Yq6oI68VdYSx5m5uwIOjAp1elQHU3G5eVPhM683Fr8n16DI/u7qJkjkPk6nFom8G6AJqcq2PU//c 2460qOKvWiG3l4GlpbE1na1aQ9RYlMpoX4uL3/l4Op4Sf6m8CsElZBYqttk3+3yDzpMFcm2WlqZH2O/T 2461yfnPK0ITKmsqFejM1JkPygW/1dR4eac2irB6CU/w1lcsLe+k+V7DYv+5OMp6qefc6X4VnsiwaulY 24626fvJXrN4bKOJ6s/Fyyrg9BTkVptvX2UEtSkJ18b8ZwkcfhTwXrKqJWuHd/+Q3T/IjLWqkHxk7f0B 2463pW9kFXTaNlwn+TjWSglSwaiMbMRP8l7yTAltE5AOc5VT8FLvDm2KC3F87VnyBzuZrUakdMERXe0P 24647luSN+leWsYF5x/QAQdqeoHC4JZYKrr5+uq6t9mQXT/T8VrWHMRwmoqO9yGTUHF8YN/EHPbFI/bz 2465/no= 2466""" 2467) 2468 2469# file python-config 2470PYTHON_CONFIG = convert( 2471 """ 2472eJyNVV1P2zAUfc+v8ODBiSABxlulTipbO6p1LWqBgVhlhcZpPYUkctzSivHfd6+dpGloGH2Ja/ue 2473e+65Hz78xNhtf3x90xmw7vCWsRPGLvpDNuz87MKfdKMWSWxZ4ilNpCLZJiuWc66SVFUOZkkcirll 2474rfxIBAzOMtImDzSVPBRrekwoX/OZu/0r4lm0DHiG60g86u8sjPw5rCyy86NRkB8QuuBRSqfAKESn 24753orLTCQxE3GYkC9tYp8fk89OSwNsmXgizrhUtnumeSgeo5GbLUMk49Rv+2nK48Cm/qMwfp333J2/ 2476dVcAGE0CIQHBsgIeEr4Wij0LtWDLzJ9ze5YEvH2WI6CHTAVcSu9ZCsXtgxu81CIvp6/k4eXsdfo7 2477PvDCRD75yi41QitfzlcPp1OI7i/1/iQitqnr0iMgQ+A6wa+IKwwdxyk9IiXNAzgquTFU8NIxAVjM 2478osm1Zz526e+shQ4hKRVci69nPC3Kw4NQEmkQ65E7OodxorSvxjvpBjQHDmWFIQ1mlmzlS5vedseT 2479/mgIEsMJ7Lxz2bLAF9M5xeLEhdbHxpWOw0GdkJApMVBRF1y+a0z3c9WZPAXGFcFrJgCIB+024uad 24800CrzmEoRa3Ub4swNIHPGf7QDV+2uj2OiFWsChgCwjKqN6rp5izpbH6Wc1O1TclQTP/XVwi6anTr1 24811sbubjZLI1+VptPSdCfwnFBrB1jvebrTA9uUhU2/9gad7xPqeFkaQcnnLbCViZK8d7R1kxzFrIJV 24828EaLYmKYpvGVkig+3C5HCXbM1jGCGekiM2pRCVPyRyXYdPf6kcbWEQ36F5V4Gq9N7icNNw+JHwRE 2483LTgxRXACpvnQv/PuT0xCCAywY/K4hE6Now2qDwaSE5FB+1agsoUveYDepS83qFcF1NufvULD3fTl 2484g6Hgf7WBt6lzMeiyyWVn3P1WVbwaczHmTzE9A5SyItTVgFYyvs/L/fXlaNgbw8v3azT+0eikVlWD 2485/vBHbzQumP23uBCjsYdrL9OWARwxs/nuLOzeXbPJTa/Xv6sUmQir5pC1YRLz3eA+CD8Z0XpcW8v9 2486MZWF36ryyXXf3yBIz6nzqz8Muyz0m5Qj7OexfYo/Ph3LqvkHUg7AuA== 2487""" 2488) 2489 2490MH_MAGIC = 0xFEEDFACE 2491MH_CIGAM = 0xCEFAEDFE 2492MH_MAGIC_64 = 0xFEEDFACF 2493MH_CIGAM_64 = 0xCFFAEDFE 2494FAT_MAGIC = 0xCAFEBABE 2495BIG_ENDIAN = ">" 2496LITTLE_ENDIAN = "<" 2497LC_LOAD_DYLIB = 0xC 2498maxint = MAJOR == 3 and getattr(sys, "maxsize") or getattr(sys, "maxint") 2499 2500 2501class FileView(object): 2502 """ 2503 A proxy for file-like objects that exposes a given view of a file. 2504 Modified from macholib. 2505 """ 2506 2507 def __init__(self, file_obj, start=0, size=maxint): 2508 if isinstance(file_obj, FileView): 2509 self._file_obj = file_obj._file_obj 2510 else: 2511 self._file_obj = file_obj 2512 self._start = start 2513 self._end = start + size 2514 self._pos = 0 2515 2516 def __repr__(self): 2517 return "<fileview [{:d}, {:d}] {!r}>".format(self._start, self._end, self._file_obj) 2518 2519 def tell(self): 2520 return self._pos 2521 2522 def _checkwindow(self, seek_to, op): 2523 if not (self._start <= seek_to <= self._end): 2524 raise IOError( 2525 "{} to offset {:d} is outside window [{:d}, {:d}]".format(op, seek_to, self._start, self._end) 2526 ) 2527 2528 def seek(self, offset, whence=0): 2529 seek_to = offset 2530 if whence == os.SEEK_SET: 2531 seek_to += self._start 2532 elif whence == os.SEEK_CUR: 2533 seek_to += self._start + self._pos 2534 elif whence == os.SEEK_END: 2535 seek_to += self._end 2536 else: 2537 raise IOError("Invalid whence argument to seek: {!r}".format(whence)) 2538 self._checkwindow(seek_to, "seek") 2539 self._file_obj.seek(seek_to) 2540 self._pos = seek_to - self._start 2541 2542 def write(self, content): 2543 here = self._start + self._pos 2544 self._checkwindow(here, "write") 2545 self._checkwindow(here + len(content), "write") 2546 self._file_obj.seek(here, os.SEEK_SET) 2547 self._file_obj.write(content) 2548 self._pos += len(content) 2549 2550 def read(self, size=maxint): 2551 assert size >= 0 2552 here = self._start + self._pos 2553 self._checkwindow(here, "read") 2554 size = min(size, self._end - here) 2555 self._file_obj.seek(here, os.SEEK_SET) 2556 read_bytes = self._file_obj.read(size) 2557 self._pos += len(read_bytes) 2558 return read_bytes 2559 2560 2561def read_data(file, endian, num=1): 2562 """ 2563 Read a given number of 32-bits unsigned integers from the given file 2564 with the given endianness. 2565 """ 2566 res = struct.unpack(endian + "L" * num, file.read(num * 4)) 2567 if len(res) == 1: 2568 return res[0] 2569 return res 2570 2571 2572def mach_o_change(at_path, what, value): 2573 """ 2574 Replace a given name (what) in any LC_LOAD_DYLIB command found in 2575 the given binary with a new name (value), provided it's shorter. 2576 """ 2577 2578 def do_macho(file, bits, endian): 2579 # Read Mach-O header (the magic number is assumed read by the caller) 2580 cpu_type, cpu_sub_type, file_type, n_commands, size_of_commands, flags = read_data(file, endian, 6) 2581 # 64-bits header has one more field. 2582 if bits == 64: 2583 read_data(file, endian) 2584 # The header is followed by n commands 2585 for _ in range(n_commands): 2586 where = file.tell() 2587 # Read command header 2588 cmd, cmd_size = read_data(file, endian, 2) 2589 if cmd == LC_LOAD_DYLIB: 2590 # The first data field in LC_LOAD_DYLIB commands is the 2591 # offset of the name, starting from the beginning of the 2592 # command. 2593 name_offset = read_data(file, endian) 2594 file.seek(where + name_offset, os.SEEK_SET) 2595 # Read the NUL terminated string 2596 load = file.read(cmd_size - name_offset).decode() 2597 load = load[: load.index("\0")] 2598 # If the string is what is being replaced, overwrite it. 2599 if load == what: 2600 file.seek(where + name_offset, os.SEEK_SET) 2601 file.write(value.encode() + "\0".encode()) 2602 # Seek to the next command 2603 file.seek(where + cmd_size, os.SEEK_SET) 2604 2605 def do_file(file, offset=0, size=maxint): 2606 file = FileView(file, offset, size) 2607 # Read magic number 2608 magic = read_data(file, BIG_ENDIAN) 2609 if magic == FAT_MAGIC: 2610 # Fat binaries contain nfat_arch Mach-O binaries 2611 n_fat_arch = read_data(file, BIG_ENDIAN) 2612 for _ in range(n_fat_arch): 2613 # Read arch header 2614 cpu_type, cpu_sub_type, offset, size, align = read_data(file, BIG_ENDIAN, 5) 2615 do_file(file, offset, size) 2616 elif magic == MH_MAGIC: 2617 do_macho(file, 32, BIG_ENDIAN) 2618 elif magic == MH_CIGAM: 2619 do_macho(file, 32, LITTLE_ENDIAN) 2620 elif magic == MH_MAGIC_64: 2621 do_macho(file, 64, BIG_ENDIAN) 2622 elif magic == MH_CIGAM_64: 2623 do_macho(file, 64, LITTLE_ENDIAN) 2624 2625 assert len(what) >= len(value) 2626 2627 with open(at_path, "r+b") as f: 2628 do_file(f) 2629 2630 2631if __name__ == "__main__": 2632 main() 2633