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