|
|
- #!/usr/bin/env python
- """Create a "virtual" Python installation"""
-
- # fmt: off
- import os # isort:skip
- import sys # isort:skip
-
- # If we are running in a new interpreter to create a virtualenv,
- # we do NOT want paths from our existing location interfering with anything,
- # So we remove this file's directory from sys.path - most likely to be
- # the previous interpreter's site-packages. Solves #705, #763, #779
- if os.environ.get("VIRTUALENV_INTERPRETER_RUNNING"):
- for path in sys.path[:]:
- if os.path.realpath(os.path.dirname(__file__)) == os.path.realpath(path):
- sys.path.remove(path)
- # fmt: on
-
- import base64
- import codecs
- import distutils.spawn
- import distutils.sysconfig
- import errno
- import glob
- import logging
- import optparse
- import os
- import re
- import shutil
- import struct
- import subprocess
- import sys
- import textwrap
- import zlib
- from distutils.util import strtobool
- from os.path import join
-
- try:
- import ConfigParser
- except ImportError:
- import configparser as ConfigParser
-
- __version__ = "16.1.0"
- virtualenv_version = __version__ # legacy
-
- if sys.version_info < (2, 7):
- print("ERROR: %s" % sys.exc_info()[1])
- print("ERROR: this script requires Python 2.7 or greater.")
- sys.exit(101)
-
- try:
- basestring
- except NameError:
- basestring = str
-
- py_version = "python{}.{}".format(sys.version_info[0], sys.version_info[1])
-
- is_jython = sys.platform.startswith("java")
- is_pypy = hasattr(sys, "pypy_version_info")
- is_win = sys.platform == "win32"
- is_cygwin = sys.platform == "cygwin"
- is_darwin = sys.platform == "darwin"
- abiflags = getattr(sys, "abiflags", "")
-
- user_dir = os.path.expanduser("~")
- if is_win:
- default_storage_dir = os.path.join(user_dir, "virtualenv")
- else:
- default_storage_dir = os.path.join(user_dir, ".virtualenv")
- default_config_file = os.path.join(default_storage_dir, "virtualenv.ini")
-
- if is_pypy:
- expected_exe = "pypy"
- elif is_jython:
- expected_exe = "jython"
- else:
- expected_exe = "python"
-
- # Return a mapping of version -> Python executable
- # Only provided for Windows, where the information in the registry is used
- if not is_win:
-
- def get_installed_pythons():
- return {}
-
-
- else:
- try:
- import winreg
- except ImportError:
- import _winreg as winreg
-
- def get_installed_pythons():
- exes = dict()
- # If both system and current user installations are found for a
- # particular Python version, the current user one is used
- for key in (winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER):
- try:
- python_core = winreg.CreateKey(key, "Software\\Python\\PythonCore")
- except WindowsError:
- # No registered Python installations
- continue
- i = 0
- while True:
- try:
- version = winreg.EnumKey(python_core, i)
- i += 1
- try:
- path = winreg.QueryValue(python_core, "%s\\InstallPath" % version)
- except WindowsError:
- continue
- exes[version] = join(path, "python.exe")
- except WindowsError:
- break
- winreg.CloseKey(python_core)
-
- # For versions that track separate 32-bit (`X.Y-32`) & 64-bit (`X-Y`)
- # installation registrations, add a `X.Y-64` version tag and make the
- # extensionless `X.Y` version tag represent the 64-bit installation if
- # available or 32-bit if it is not
- updated = {}
- for ver in exes:
- if ver < "3.5":
- continue
- if ver.endswith("-32"):
- base_ver = ver[:-3]
- if base_ver not in exes:
- updated[base_ver] = exes[ver]
- else:
- updated[ver + "-64"] = exes[ver]
- exes.update(updated)
-
- # Add the major versions
- # Sort the keys, then repeatedly update the major version entry
- # Last executable (i.e., highest version) wins with this approach,
- # 64-bit over 32-bit if both are found
- for ver in sorted(exes):
- exes[ver[0]] = exes[ver]
-
- return exes
-
-
- REQUIRED_MODULES = [
- "os",
- "posix",
- "posixpath",
- "nt",
- "ntpath",
- "genericpath",
- "fnmatch",
- "locale",
- "encodings",
- "codecs",
- "stat",
- "UserDict",
- "readline",
- "copy_reg",
- "types",
- "re",
- "sre",
- "sre_parse",
- "sre_constants",
- "sre_compile",
- "zlib",
- ]
-
- REQUIRED_FILES = ["lib-dynload", "config"]
-
- majver, minver = sys.version_info[:2]
- if majver == 2:
- if minver >= 6:
- REQUIRED_MODULES.extend(["warnings", "linecache", "_abcoll", "abc"])
- if minver >= 7:
- REQUIRED_MODULES.extend(["_weakrefset"])
- elif majver == 3:
- # Some extra modules are needed for Python 3, but different ones
- # for different versions.
- REQUIRED_MODULES.extend(
- [
- "_abcoll",
- "warnings",
- "linecache",
- "abc",
- "io",
- "_weakrefset",
- "copyreg",
- "tempfile",
- "random",
- "__future__",
- "collections",
- "keyword",
- "tarfile",
- "shutil",
- "struct",
- "copy",
- "tokenize",
- "token",
- "functools",
- "heapq",
- "bisect",
- "weakref",
- "reprlib",
- ]
- )
- if minver >= 2:
- REQUIRED_FILES[-1] = "config-%s" % majver
- if minver >= 3:
- import sysconfig
-
- platdir = sysconfig.get_config_var("PLATDIR")
- REQUIRED_FILES.append(platdir)
- REQUIRED_MODULES.extend(["base64", "_dummy_thread", "hashlib", "hmac", "imp", "importlib", "rlcompleter"])
- if minver >= 4:
- REQUIRED_MODULES.extend(["operator", "_collections_abc", "_bootlocale"])
- if minver >= 6:
- REQUIRED_MODULES.extend(["enum"])
-
- if is_pypy:
- # these are needed to correctly display the exceptions that may happen
- # during the bootstrap
- REQUIRED_MODULES.extend(["traceback", "linecache"])
-
- if majver == 3:
- # _functools is needed to import locale during stdio initialization and
- # needs to be copied on PyPy because it's not built in
- REQUIRED_MODULES.append("_functools")
-
-
- class Logger(object):
-
- """
- Logging object for use in command-line script. Allows ranges of
- levels, to avoid some redundancy of displayed information.
- """
-
- DEBUG = logging.DEBUG
- INFO = logging.INFO
- NOTIFY = (logging.INFO + logging.WARN) / 2
- WARN = WARNING = logging.WARN
- ERROR = logging.ERROR
- FATAL = logging.FATAL
-
- LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
-
- def __init__(self, consumers):
- self.consumers = consumers
- self.indent = 0
- self.in_progress = None
- self.in_progress_hanging = False
-
- def debug(self, msg, *args, **kw):
- self.log(self.DEBUG, msg, *args, **kw)
-
- def info(self, msg, *args, **kw):
- self.log(self.INFO, msg, *args, **kw)
-
- def notify(self, msg, *args, **kw):
- self.log(self.NOTIFY, msg, *args, **kw)
-
- def warn(self, msg, *args, **kw):
- self.log(self.WARN, msg, *args, **kw)
-
- def error(self, msg, *args, **kw):
- self.log(self.ERROR, msg, *args, **kw)
-
- def fatal(self, msg, *args, **kw):
- self.log(self.FATAL, msg, *args, **kw)
-
- def log(self, level, msg, *args, **kw):
- if args:
- if kw:
- raise TypeError("You may give positional or keyword arguments, not both")
- args = args or kw
- rendered = None
- for consumer_level, consumer in self.consumers:
- if self.level_matches(level, consumer_level):
- if self.in_progress_hanging and consumer in (sys.stdout, sys.stderr):
- self.in_progress_hanging = False
- print("")
- sys.stdout.flush()
- if rendered is None:
- if args:
- rendered = msg % args
- else:
- rendered = msg
- rendered = " " * self.indent + rendered
- if hasattr(consumer, "write"):
- consumer.write(rendered + "\n")
- else:
- consumer(rendered)
-
- def start_progress(self, msg):
- assert not self.in_progress, "Tried to start_progress({!r}) while in_progress {!r}".format(
- msg, self.in_progress
- )
- if self.level_matches(self.NOTIFY, self._stdout_level()):
- print(msg)
- sys.stdout.flush()
- self.in_progress_hanging = True
- else:
- self.in_progress_hanging = False
- self.in_progress = msg
-
- def end_progress(self, msg="done."):
- assert self.in_progress, "Tried to end_progress without start_progress"
- if self.stdout_level_matches(self.NOTIFY):
- if not self.in_progress_hanging:
- # Some message has been printed out since start_progress
- print("...{}{}".format(self.in_progress, msg))
- sys.stdout.flush()
- else:
- print(msg)
- sys.stdout.flush()
- self.in_progress = None
- self.in_progress_hanging = False
-
- def show_progress(self):
- """If we are in a progress scope, and no log messages have been
- shown, write out another '.'"""
- if self.in_progress_hanging:
- print(".")
- sys.stdout.flush()
-
- def stdout_level_matches(self, level):
- """Returns true if a message at this level will go to stdout"""
- return self.level_matches(level, self._stdout_level())
-
- def _stdout_level(self):
- """Returns the level that stdout runs at"""
- for level, consumer in self.consumers:
- if consumer is sys.stdout:
- return level
- return self.FATAL
-
- def level_matches(self, level, consumer_level):
- """
- >>> l = Logger([])
- >>> l.level_matches(3, 4)
- False
- >>> l.level_matches(3, 2)
- True
- >>> l.level_matches(slice(None, 3), 3)
- False
- >>> l.level_matches(slice(None, 3), 2)
- True
- >>> l.level_matches(slice(1, 3), 1)
- True
- >>> l.level_matches(slice(2, 3), 1)
- False
- """
- if isinstance(level, slice):
- start, stop = level.start, level.stop
- if start is not None and start > consumer_level:
- return False
- if stop is not None and stop <= consumer_level:
- return False
- return True
- else:
- return level >= consumer_level
-
- @classmethod
- def level_for_integer(cls, level):
- levels = cls.LEVELS
- if level < 0:
- return levels[0]
- if level >= len(levels):
- return levels[-1]
- return levels[level]
-
-
- # create a silent logger just to prevent this from being undefined
- # will be overridden with requested verbosity main() is called.
- logger = Logger([(Logger.LEVELS[-1], sys.stdout)])
-
-
- def mkdir(path):
- if not os.path.exists(path):
- logger.info("Creating %s", path)
- os.makedirs(path)
- else:
- logger.info("Directory %s already exists", path)
-
-
- def copyfileordir(src, dest, symlink=True):
- if os.path.isdir(src):
- shutil.copytree(src, dest, symlink)
- else:
- shutil.copy2(src, dest)
-
-
- def copyfile(src, dest, symlink=True):
- if not os.path.exists(src):
- # Some bad symlink in the src
- logger.warn("Cannot find file %s (bad symlink)", src)
- return
- if os.path.exists(dest):
- logger.debug("File %s already exists", dest)
- return
- if not os.path.exists(os.path.dirname(dest)):
- logger.info("Creating parent directories for %s", os.path.dirname(dest))
- os.makedirs(os.path.dirname(dest))
- if not os.path.islink(src):
- srcpath = os.path.abspath(src)
- else:
- srcpath = os.readlink(src)
- if symlink and hasattr(os, "symlink") and not is_win:
- logger.info("Symlinking %s", dest)
- try:
- os.symlink(srcpath, dest)
- except (OSError, NotImplementedError):
- logger.info("Symlinking failed, copying to %s", dest)
- copyfileordir(src, dest, symlink)
- else:
- logger.info("Copying to %s", dest)
- copyfileordir(src, dest, symlink)
-
-
- def writefile(dest, content, overwrite=True):
- if not os.path.exists(dest):
- logger.info("Writing %s", dest)
- with open(dest, "wb") as f:
- f.write(content.encode("utf-8"))
- return
- else:
- with open(dest, "rb") as f:
- c = f.read()
- if c != content.encode("utf-8"):
- if not overwrite:
- logger.notify("File %s exists with different content; not overwriting", dest)
- return
- logger.notify("Overwriting %s with new content", dest)
- with open(dest, "wb") as f:
- f.write(content.encode("utf-8"))
- else:
- logger.info("Content %s already in place", dest)
-
-
- def rmtree(dir):
- if os.path.exists(dir):
- logger.notify("Deleting tree %s", dir)
- shutil.rmtree(dir)
- else:
- logger.info("Do not need to delete %s; already gone", dir)
-
-
- def make_exe(fn):
- if hasattr(os, "chmod"):
- oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777
- newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777
- os.chmod(fn, newmode)
- logger.info("Changed mode of %s to %s", fn, oct(newmode))
-
-
- def _find_file(filename, dirs):
- for dir in reversed(dirs):
- files = glob.glob(os.path.join(dir, filename))
- if files and os.path.isfile(files[0]):
- return True, files[0]
- return False, filename
-
-
- def file_search_dirs():
- here = os.path.dirname(os.path.abspath(__file__))
- dirs = [here, join(here, "virtualenv_support")]
- if os.path.splitext(os.path.dirname(__file__))[0] != "virtualenv":
- # Probably some boot script; just in case virtualenv is installed...
- try:
- import virtualenv
- except ImportError:
- pass
- else:
- dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), "virtualenv_support"))
- return [d for d in dirs if os.path.isdir(d)]
-
-
- class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):
- """
- Custom help formatter for use in ConfigOptionParser that updates
- the defaults before expanding them, allowing them to show up correctly
- in the help listing
- """
-
- def expand_default(self, option):
- if self.parser is not None:
- self.parser.update_defaults(self.parser.defaults)
- return optparse.IndentedHelpFormatter.expand_default(self, option)
-
-
- class ConfigOptionParser(optparse.OptionParser):
- """
- Custom option parser which updates its defaults by checking the
- configuration files and environmental variables
- """
-
- def __init__(self, *args, **kwargs):
- self.config = ConfigParser.RawConfigParser()
- self.files = self.get_config_files()
- self.config.read(self.files)
- optparse.OptionParser.__init__(self, *args, **kwargs)
-
- def get_config_files(self):
- config_file = os.environ.get("VIRTUALENV_CONFIG_FILE", False)
- if config_file and os.path.exists(config_file):
- return [config_file]
- return [default_config_file]
-
- def update_defaults(self, defaults):
- """
- Updates the given defaults with values from the config files and
- the environ. Does a little special handling for certain types of
- options (lists).
- """
- # Then go and look for the other sources of configuration:
- config = {}
- # 1. config files
- config.update(dict(self.get_config_section("virtualenv")))
- # 2. environmental variables
- config.update(dict(self.get_environ_vars()))
- # Then set the options with those values
- for key, val in config.items():
- key = key.replace("_", "-")
- if not key.startswith("--"):
- key = "--%s" % key # only prefer long opts
- option = self.get_option(key)
- if option is not None:
- # ignore empty values
- if not val:
- continue
- # handle multiline configs
- if option.action == "append":
- val = val.split()
- else:
- option.nargs = 1
- if option.action == "store_false":
- val = not strtobool(val)
- elif option.action in ("store_true", "count"):
- val = strtobool(val)
- try:
- val = option.convert_value(key, val)
- except optparse.OptionValueError:
- e = sys.exc_info()[1]
- print("An error occurred during configuration: %s" % e)
- sys.exit(3)
- defaults[option.dest] = val
- return defaults
-
- def get_config_section(self, name):
- """
- Get a section of a configuration
- """
- if self.config.has_section(name):
- return self.config.items(name)
- return []
-
- def get_environ_vars(self, prefix="VIRTUALENV_"):
- """
- Returns a generator with all environmental vars with prefix VIRTUALENV
- """
- for key, val in os.environ.items():
- if key.startswith(prefix):
- yield (key.replace(prefix, "").lower(), val)
-
- def get_default_values(self):
- """
- Overridding to make updating the defaults after instantiation of
- the option parser possible, update_defaults() does the dirty work.
- """
- if not self.process_default_values:
- # Old, pre-Optik 1.5 behaviour.
- return optparse.Values(self.defaults)
-
- defaults = self.update_defaults(self.defaults.copy()) # ours
- for option in self._get_all_options():
- default = defaults.get(option.dest)
- if isinstance(default, basestring):
- opt_str = option.get_opt_string()
- defaults[option.dest] = option.check_value(opt_str, default)
- return optparse.Values(defaults)
-
-
- def main():
- parser = ConfigOptionParser(
- version=virtualenv_version, usage="%prog [OPTIONS] DEST_DIR", formatter=UpdatingDefaultsHelpFormatter()
- )
-
- parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0, help="Increase verbosity.")
-
- parser.add_option("-q", "--quiet", action="count", dest="quiet", default=0, help="Decrease verbosity.")
-
- parser.add_option(
- "-p",
- "--python",
- dest="python",
- metavar="PYTHON_EXE",
- help="The Python interpreter to use, e.g., --python=python3.5 will use the python3.5 "
- "interpreter to create the new environment. The default is the interpreter that "
- "virtualenv was installed with (%s)" % sys.executable,
- )
-
- parser.add_option(
- "--clear", dest="clear", action="store_true", help="Clear out the non-root install and start from scratch."
- )
-
- parser.set_defaults(system_site_packages=False)
- parser.add_option(
- "--no-site-packages",
- dest="system_site_packages",
- action="store_false",
- help="DEPRECATED. Retained only for backward compatibility. "
- "Not having access to global site-packages is now the default behavior.",
- )
-
- parser.add_option(
- "--system-site-packages",
- dest="system_site_packages",
- action="store_true",
- help="Give the virtual environment access to the global site-packages.",
- )
-
- parser.add_option(
- "--always-copy",
- dest="symlink",
- action="store_false",
- default=True,
- help="Always copy files rather than symlinking.",
- )
-
- parser.add_option(
- "--relocatable",
- dest="relocatable",
- action="store_true",
- help="Make an EXISTING virtualenv environment relocatable. "
- "This fixes up scripts and makes all .pth files relative.",
- )
-
- parser.add_option(
- "--no-setuptools",
- dest="no_setuptools",
- action="store_true",
- help="Do not install setuptools in the new virtualenv.",
- )
-
- parser.add_option("--no-pip", dest="no_pip", action="store_true", help="Do not install pip in the new virtualenv.")
-
- parser.add_option(
- "--no-wheel", dest="no_wheel", action="store_true", help="Do not install wheel in the new virtualenv."
- )
-
- default_search_dirs = file_search_dirs()
- parser.add_option(
- "--extra-search-dir",
- dest="search_dirs",
- action="append",
- metavar="DIR",
- default=default_search_dirs,
- help="Directory to look for setuptools/pip distributions in. " "This option can be used multiple times.",
- )
-
- parser.add_option(
- "--download",
- dest="download",
- default=True,
- action="store_true",
- help="Download preinstalled packages from PyPI.",
- )
-
- parser.add_option(
- "--no-download",
- "--never-download",
- dest="download",
- action="store_false",
- help="Do not download preinstalled packages from PyPI.",
- )
-
- parser.add_option("--prompt", dest="prompt", help="Provides an alternative prompt prefix for this environment.")
-
- parser.add_option(
- "--setuptools",
- dest="setuptools",
- action="store_true",
- help="DEPRECATED. Retained only for backward compatibility. This option has no effect.",
- )
-
- parser.add_option(
- "--distribute",
- dest="distribute",
- action="store_true",
- help="DEPRECATED. Retained only for backward compatibility. This option has no effect.",
- )
-
- parser.add_option(
- "--unzip-setuptools",
- action="store_true",
- help="DEPRECATED. Retained only for backward compatibility. This option has no effect.",
- )
-
- if "extend_parser" in globals():
- extend_parser(parser) # noqa: F821
-
- options, args = parser.parse_args()
-
- global logger
-
- if "adjust_options" in globals():
- adjust_options(options, args) # noqa: F821
-
- verbosity = options.verbose - options.quiet
- logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)])
-
- if options.python and not os.environ.get("VIRTUALENV_INTERPRETER_RUNNING"):
- env = os.environ.copy()
- interpreter = resolve_interpreter(options.python)
- if interpreter == sys.executable:
- logger.warn("Already using interpreter %s" % interpreter)
- else:
- logger.notify("Running virtualenv with interpreter %s" % interpreter)
- env["VIRTUALENV_INTERPRETER_RUNNING"] = "true"
- file = __file__
- if file.endswith(".pyc"):
- file = file[:-1]
- popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
- raise SystemExit(popen.wait())
-
- if not args:
- print("You must provide a DEST_DIR")
- parser.print_help()
- sys.exit(2)
- if len(args) > 1:
- print("There must be only one argument: DEST_DIR (you gave %s)" % (" ".join(args)))
- parser.print_help()
- sys.exit(2)
-
- home_dir = args[0]
-
- if os.path.exists(home_dir) and os.path.isfile(home_dir):
- logger.fatal("ERROR: File already exists and is not a directory.")
- logger.fatal("Please provide a different path or delete the file.")
- sys.exit(3)
-
- if os.environ.get("WORKING_ENV"):
- logger.fatal("ERROR: you cannot run virtualenv while in a workingenv")
- logger.fatal("Please deactivate your workingenv, then re-run this script")
- sys.exit(3)
-
- if "PYTHONHOME" in os.environ:
- logger.warn("PYTHONHOME is set. You *must* activate the virtualenv before using it")
- del os.environ["PYTHONHOME"]
-
- if options.relocatable:
- make_environment_relocatable(home_dir)
- return
-
- create_environment(
- home_dir,
- site_packages=options.system_site_packages,
- clear=options.clear,
- prompt=options.prompt,
- search_dirs=options.search_dirs,
- download=options.download,
- no_setuptools=options.no_setuptools,
- no_pip=options.no_pip,
- no_wheel=options.no_wheel,
- symlink=options.symlink,
- )
- if "after_install" in globals():
- after_install(options, home_dir) # noqa: F821
-
-
- def call_subprocess(
- cmd,
- show_stdout=True,
- filter_stdout=None,
- cwd=None,
- raise_on_returncode=True,
- extra_env=None,
- remove_from_env=None,
- stdin=None,
- ):
- cmd_parts = []
- for part in cmd:
- if len(part) > 45:
- part = part[:20] + "..." + part[-20:]
- if " " in part or "\n" in part or '"' in part or "'" in part:
- part = '"%s"' % part.replace('"', '\\"')
- if hasattr(part, "decode"):
- try:
- part = part.decode(sys.getdefaultencoding())
- except UnicodeDecodeError:
- part = part.decode(sys.getfilesystemencoding())
- cmd_parts.append(part)
- cmd_desc = " ".join(cmd_parts)
- if show_stdout:
- stdout = None
- else:
- stdout = subprocess.PIPE
- logger.debug("Running command %s" % cmd_desc)
- if extra_env or remove_from_env:
- env = os.environ.copy()
- if extra_env:
- env.update(extra_env)
- if remove_from_env:
- for varname in remove_from_env:
- env.pop(varname, None)
- else:
- env = None
- try:
- proc = subprocess.Popen(
- cmd,
- stderr=subprocess.STDOUT,
- stdin=None if stdin is None else subprocess.PIPE,
- stdout=stdout,
- cwd=cwd,
- env=env,
- )
- except Exception:
- e = sys.exc_info()[1]
- logger.fatal("Error {} while executing command {}".format(e, cmd_desc))
- raise
- all_output = []
- if stdout is not None:
- if stdin is not None:
- proc.stdin.write(stdin)
- proc.stdin.close()
-
- stdout = proc.stdout
- encoding = sys.getdefaultencoding()
- fs_encoding = sys.getfilesystemencoding()
- while 1:
- line = stdout.readline()
- try:
- line = line.decode(encoding)
- except UnicodeDecodeError:
- line = line.decode(fs_encoding)
- if not line:
- break
- line = line.rstrip()
- all_output.append(line)
- if filter_stdout:
- level = filter_stdout(line)
- if isinstance(level, tuple):
- level, line = level
- logger.log(level, line)
- if not logger.stdout_level_matches(level):
- logger.show_progress()
- else:
- logger.info(line)
- else:
- proc.communicate(stdin)
- proc.wait()
- if proc.returncode:
- if raise_on_returncode:
- if all_output:
- logger.notify("Complete output from command %s:" % cmd_desc)
- logger.notify("\n".join(all_output) + "\n----------------------------------------")
- raise OSError("Command {} failed with error code {}".format(cmd_desc, proc.returncode))
- else:
- logger.warn("Command {} had error code {}".format(cmd_desc, proc.returncode))
-
-
- def filter_install_output(line):
- if line.strip().startswith("running"):
- return Logger.INFO
- return Logger.DEBUG
-
-
- def find_wheels(projects, search_dirs):
- """Find wheels from which we can import PROJECTS.
-
- Scan through SEARCH_DIRS for a wheel for each PROJECT in turn. Return
- a list of the first wheel found for each PROJECT
- """
-
- wheels = []
-
- # Look through SEARCH_DIRS for the first suitable wheel. Don't bother
- # about version checking here, as this is simply to get something we can
- # then use to install the correct version.
- for project in projects:
- for dirname in search_dirs:
- # This relies on only having "universal" wheels available.
- # The pattern could be tightened to require -py2.py3-none-any.whl.
- files = glob.glob(os.path.join(dirname, project + "-*.whl"))
- if files:
- wheels.append(os.path.abspath(files[0]))
- break
- else:
- # We're out of luck, so quit with a suitable error
- logger.fatal("Cannot find a wheel for {}".format(project))
-
- return wheels
-
-
- def install_wheel(project_names, py_executable, search_dirs=None, download=False):
- if search_dirs is None:
- search_dirs = file_search_dirs()
-
- wheels = find_wheels(["setuptools", "pip"], search_dirs)
- python_path = os.pathsep.join(wheels)
-
- # PIP_FIND_LINKS uses space as the path separator and thus cannot have paths
- # with spaces in them. Convert any of those to local file:// URL form.
- try:
- from urlparse import urljoin
- from urllib import pathname2url
- except ImportError:
- from urllib.parse import urljoin
- from urllib.request import pathname2url
-
- def space_path2url(p):
- if " " not in p:
- return p
- return urljoin("file:", pathname2url(os.path.abspath(p)))
-
- findlinks = " ".join(space_path2url(d) for d in search_dirs)
- SCRIPT = textwrap.dedent(
- """
- import sys
- import pkgutil
- import tempfile
- import os
-
- try:
- from pip._internal import main as _main
- cert_data = pkgutil.get_data("pip._vendor.certifi", "cacert.pem")
- except ImportError:
- from pip import main as _main
- cert_data = pkgutil.get_data("pip._vendor.requests", "cacert.pem")
-
- if cert_data is not None:
- cert_file = tempfile.NamedTemporaryFile(delete=False)
- cert_file.write(cert_data)
- cert_file.close()
- else:
- cert_file = None
-
- try:
- args = ["install", "--ignore-installed"]
- if cert_file is not None:
- args += ["--cert", cert_file.name{}]
- args += sys.argv[1:]
-
- sys.exit(_main(args))
- finally:
- if cert_file is not None:
- os.remove(cert_file.name)
- """.format(
- ", '--no-cache'" if is_jython else ""
- )
- ).encode("utf8")
-
- cmd = [py_executable, "-"] + project_names
- logger.start_progress("Installing %s..." % (", ".join(project_names)))
- logger.indent += 2
-
- env = {
- "PYTHONPATH": python_path,
- "JYTHONPATH": python_path, # for Jython < 3.x
- "PIP_FIND_LINKS": findlinks,
- "PIP_USE_WHEEL": "1",
- "PIP_ONLY_BINARY": ":all:",
- "PIP_USER": "0",
- "PIP_NO_INPUT": "1",
- }
-
- if not download:
- env["PIP_NO_INDEX"] = "1"
-
- try:
- call_subprocess(cmd, show_stdout=False, extra_env=env, stdin=SCRIPT)
- finally:
- logger.indent -= 2
- logger.end_progress()
-
-
- def create_environment(
- home_dir,
- site_packages=False,
- clear=False,
- prompt=None,
- search_dirs=None,
- download=False,
- no_setuptools=False,
- no_pip=False,
- no_wheel=False,
- symlink=True,
- ):
- """
- Creates a new environment in ``home_dir``.
-
- If ``site_packages`` is true, then the global ``site-packages/``
- directory will be on the path.
-
- If ``clear`` is true (default False) then the environment will
- first be cleared.
- """
- home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
-
- py_executable = os.path.abspath(
- install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages=site_packages, clear=clear, symlink=symlink)
- )
-
- install_distutils(home_dir)
-
- to_install = []
-
- if not no_setuptools:
- to_install.append("setuptools")
-
- if not no_pip:
- to_install.append("pip")
-
- if not no_wheel:
- to_install.append("wheel")
-
- if to_install:
- install_wheel(to_install, py_executable, search_dirs, download=download)
-
- install_activate(home_dir, bin_dir, prompt)
-
- install_python_config(home_dir, bin_dir, prompt)
-
-
- def is_executable_file(fpath):
- return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
-
-
- def path_locations(home_dir, dry_run=False):
- """Return the path locations for the environment (where libraries are,
- where scripts go, etc)"""
- home_dir = os.path.abspath(home_dir)
- # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
- # prefix arg is broken: http://bugs.python.org/issue3386
- if is_win:
- # Windows has lots of problems with executables with spaces in
- # the name; this function will remove them (using the ~1
- # format):
- if not dry_run:
- mkdir(home_dir)
- if " " in home_dir:
- import ctypes
-
- GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW
- size = max(len(home_dir) + 1, 256)
- buf = ctypes.create_unicode_buffer(size)
- try:
- u = unicode
- except NameError:
- u = str
- ret = GetShortPathName(u(home_dir), buf, size)
- if not ret:
- print('Error: the path "%s" has a space in it' % home_dir)
- print("We could not determine the short pathname for it.")
- print("Exiting.")
- sys.exit(3)
- home_dir = str(buf.value)
- lib_dir = join(home_dir, "Lib")
- inc_dir = join(home_dir, "Include")
- bin_dir = join(home_dir, "Scripts")
- if is_jython:
- lib_dir = join(home_dir, "Lib")
- inc_dir = join(home_dir, "Include")
- bin_dir = join(home_dir, "bin")
- elif is_pypy:
- lib_dir = home_dir
- inc_dir = join(home_dir, "include")
- bin_dir = join(home_dir, "bin")
- elif not is_win:
- lib_dir = join(home_dir, "lib", py_version)
- inc_dir = join(home_dir, "include", py_version + abiflags)
- bin_dir = join(home_dir, "bin")
- return home_dir, lib_dir, inc_dir, bin_dir
-
-
- def change_prefix(filename, dst_prefix):
- prefixes = [sys.prefix]
-
- if is_darwin:
- prefixes.extend(
- (
- os.path.join("/Library/Python", sys.version[:3], "site-packages"),
- os.path.join(sys.prefix, "Extras", "lib", "python"),
- os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"),
- # Python 2.6 no-frameworks
- os.path.join("~", ".local", "lib", "python", sys.version[:3], "site-packages"),
- # System Python 2.7 on OSX Mountain Lion
- os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages"),
- )
- )
-
- if hasattr(sys, "real_prefix"):
- prefixes.append(sys.real_prefix)
- if hasattr(sys, "base_prefix"):
- prefixes.append(sys.base_prefix)
- prefixes = list(map(os.path.expanduser, prefixes))
- prefixes = list(map(os.path.abspath, prefixes))
- # Check longer prefixes first so we don't split in the middle of a filename
- prefixes = sorted(prefixes, key=len, reverse=True)
- filename = os.path.abspath(filename)
- # On Windows, make sure drive letter is uppercase
- if is_win and filename[0] in "abcdefghijklmnopqrstuvwxyz":
- filename = filename[0].upper() + filename[1:]
- for i, prefix in enumerate(prefixes):
- if is_win and prefix[0] in "abcdefghijklmnopqrstuvwxyz":
- prefixes[i] = prefix[0].upper() + prefix[1:]
- for src_prefix in prefixes:
- if filename.startswith(src_prefix):
- _, relpath = filename.split(src_prefix, 1)
- if src_prefix != os.sep: # sys.prefix == "/"
- assert relpath[0] == os.sep
- relpath = relpath[1:]
- return join(dst_prefix, relpath)
- assert False, "Filename {} does not start with any of these prefixes: {}".format(filename, prefixes)
-
-
- def copy_required_modules(dst_prefix, symlink):
- import warnings
-
- with warnings.catch_warnings():
- # Ignore deprecation of the imp module
- # TODO: do not use deprecated imp module
- warnings.simplefilter("ignore")
- import imp
-
- for modname in REQUIRED_MODULES:
- if modname in sys.builtin_module_names:
- logger.info("Ignoring built-in bootstrap module: %s" % modname)
- continue
- try:
- f, filename, _ = imp.find_module(modname)
- except ImportError:
- logger.info("Cannot import bootstrap module: %s" % modname)
- else:
- if f is not None:
- f.close()
- # special-case custom readline.so on OS X, but not for pypy:
- if (
- modname == "readline"
- and sys.platform == "darwin"
- and not (is_pypy or filename.endswith(join("lib-dynload", "readline.so")))
- ):
- dst_filename = join(dst_prefix, "lib", "python%s" % sys.version[:3], "readline.so")
- elif modname == "readline" and sys.platform == "win32":
- # special-case for Windows, where readline is not a
- # standard module, though it may have been installed in
- # site-packages by a third-party package
- pass
- else:
- dst_filename = change_prefix(filename, dst_prefix)
- copyfile(filename, dst_filename, symlink)
- if filename.endswith(".pyc"):
- pyfile = filename[:-1]
- if os.path.exists(pyfile):
- copyfile(pyfile, dst_filename[:-1], symlink)
-
-
- def copy_tcltk(src, dest, symlink):
- """ copy tcl/tk libraries on Windows (issue #93) """
- for libversion in "8.5", "8.6":
- for libname in "tcl", "tk":
- srcdir = join(src, "tcl", libname + libversion)
- destdir = join(dest, "tcl", libname + libversion)
- # Only copy the dirs from the above combinations that exist
- if os.path.exists(srcdir) and not os.path.exists(destdir):
- copyfileordir(srcdir, destdir, symlink)
-
-
- def subst_path(prefix_path, prefix, home_dir):
- prefix_path = os.path.normpath(prefix_path)
- prefix = os.path.normpath(prefix)
- home_dir = os.path.normpath(home_dir)
- if not prefix_path.startswith(prefix):
- logger.warn("Path not in prefix %r %r", prefix_path, prefix)
- return
- return prefix_path.replace(prefix, home_dir, 1)
-
-
- def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, symlink=True):
- """Install just the base environment, no distutils patches etc"""
- if sys.executable.startswith(bin_dir):
- print("Please use the *system* python to run this script")
- return
-
- if clear:
- rmtree(lib_dir)
- # FIXME: why not delete it?
- # Maybe it should delete everything with #!/path/to/venv/python in it
- logger.notify("Not deleting %s", bin_dir)
-
- if hasattr(sys, "real_prefix"):
- logger.notify("Using real prefix %r" % sys.real_prefix)
- prefix = sys.real_prefix
- elif hasattr(sys, "base_prefix"):
- logger.notify("Using base prefix %r" % sys.base_prefix)
- prefix = sys.base_prefix
- else:
- prefix = sys.prefix
- prefix = os.path.abspath(prefix)
- mkdir(lib_dir)
- fix_lib64(lib_dir, symlink)
- stdlib_dirs = [os.path.dirname(os.__file__)]
- if is_win:
- stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), "DLLs"))
- elif is_darwin:
- stdlib_dirs.append(join(stdlib_dirs[0], "site-packages"))
- if hasattr(os, "symlink"):
- logger.info("Symlinking Python bootstrap modules")
- else:
- logger.info("Copying Python bootstrap modules")
- logger.indent += 2
- try:
- # copy required files...
- for stdlib_dir in stdlib_dirs:
- if not os.path.isdir(stdlib_dir):
- continue
- for fn in os.listdir(stdlib_dir):
- bn = os.path.splitext(fn)[0]
- if fn != "site-packages" and bn in REQUIRED_FILES:
- copyfile(join(stdlib_dir, fn), join(lib_dir, fn), symlink)
- # ...and modules
- copy_required_modules(home_dir, symlink)
- finally:
- logger.indent -= 2
- # ...copy tcl/tk
- if is_win:
- copy_tcltk(prefix, home_dir, symlink)
- mkdir(join(lib_dir, "site-packages"))
- import site
-
- site_filename = site.__file__
- if site_filename.endswith(".pyc") or site_filename.endswith(".pyo"):
- site_filename = site_filename[:-1]
- elif site_filename.endswith("$py.class"):
- site_filename = site_filename.replace("$py.class", ".py")
- site_filename_dst = change_prefix(site_filename, home_dir)
- site_dir = os.path.dirname(site_filename_dst)
- writefile(site_filename_dst, SITE_PY)
- writefile(join(site_dir, "orig-prefix.txt"), prefix)
- site_packages_filename = join(site_dir, "no-global-site-packages.txt")
- if not site_packages:
- writefile(site_packages_filename, "")
-
- if is_pypy or is_win:
- stdinc_dir = join(prefix, "include")
- else:
- stdinc_dir = join(prefix, "include", py_version + abiflags)
- if os.path.exists(stdinc_dir):
- copyfile(stdinc_dir, inc_dir, symlink)
- else:
- logger.debug("No include dir %s" % stdinc_dir)
-
- platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1)
- if platinc_dir != stdinc_dir:
- platinc_dest = distutils.sysconfig.get_python_inc(plat_specific=1, prefix=home_dir)
- if platinc_dir == platinc_dest:
- # Do platinc_dest manually due to a CPython bug;
- # not http://bugs.python.org/issue3386 but a close cousin
- platinc_dest = subst_path(platinc_dir, prefix, home_dir)
- if platinc_dest:
- # PyPy's stdinc_dir and prefix are relative to the original binary
- # (traversing virtualenvs), whereas the platinc_dir is relative to
- # the inner virtualenv and ignores the prefix argument.
- # This seems more evolved than designed.
- copyfile(platinc_dir, platinc_dest, symlink)
-
- # pypy never uses exec_prefix, just ignore it
- if sys.exec_prefix != prefix and not is_pypy:
- if is_win:
- exec_dir = join(sys.exec_prefix, "lib")
- elif is_jython:
- exec_dir = join(sys.exec_prefix, "Lib")
- else:
- exec_dir = join(sys.exec_prefix, "lib", py_version)
- if os.path.isdir(exec_dir):
- for fn in os.listdir(exec_dir):
- copyfile(join(exec_dir, fn), join(lib_dir, fn), symlink)
-
- if is_jython:
- # Jython has either jython-dev.jar and javalib/ dir, or just
- # jython.jar
- for name in "jython-dev.jar", "javalib", "jython.jar":
- src = join(prefix, name)
- if os.path.exists(src):
- copyfile(src, join(home_dir, name), symlink)
- # XXX: registry should always exist after Jython 2.5rc1
- src = join(prefix, "registry")
- if os.path.exists(src):
- copyfile(src, join(home_dir, "registry"), symlink=False)
- copyfile(join(prefix, "cachedir"), join(home_dir, "cachedir"), symlink=False)
-
- mkdir(bin_dir)
- py_executable = join(bin_dir, os.path.basename(sys.executable))
- if "Python.framework" in prefix:
- # OS X framework builds cause validation to break
- # https://github.com/pypa/virtualenv/issues/322
- if os.environ.get("__PYVENV_LAUNCHER__"):
- del os.environ["__PYVENV_LAUNCHER__"]
- if re.search(r"/Python(?:-32|-64)*$", py_executable):
- # The name of the python executable is not quite what
- # we want, rename it.
- py_executable = os.path.join(os.path.dirname(py_executable), "python")
-
- logger.notify("New %s executable in %s", expected_exe, py_executable)
- pcbuild_dir = os.path.dirname(sys.executable)
- pyd_pth = os.path.join(lib_dir, "site-packages", "virtualenv_builddir_pyd.pth")
- if is_win and os.path.exists(os.path.join(pcbuild_dir, "build.bat")):
- logger.notify("Detected python running from build directory %s", pcbuild_dir)
- logger.notify("Writing .pth file linking to build directory for *.pyd files")
- writefile(pyd_pth, pcbuild_dir)
- else:
- pcbuild_dir = None
- if os.path.exists(pyd_pth):
- logger.info("Deleting %s (not Windows env or not build directory python)" % pyd_pth)
- os.unlink(pyd_pth)
-
- if sys.executable != py_executable:
- # FIXME: could I just hard link?
- executable = sys.executable
- shutil.copyfile(executable, py_executable)
- make_exe(py_executable)
- if is_win or is_cygwin:
- pythonw = os.path.join(os.path.dirname(sys.executable), "pythonw.exe")
- if os.path.exists(pythonw):
- logger.info("Also created pythonw.exe")
- shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), "pythonw.exe"))
- python_d = os.path.join(os.path.dirname(sys.executable), "python_d.exe")
- python_d_dest = os.path.join(os.path.dirname(py_executable), "python_d.exe")
- if os.path.exists(python_d):
- logger.info("Also created python_d.exe")
- shutil.copyfile(python_d, python_d_dest)
- elif os.path.exists(python_d_dest):
- logger.info("Removed python_d.exe as it is no longer at the source")
- os.unlink(python_d_dest)
-
- # we need to copy the DLL to enforce that windows will load the correct one.
- # may not exist if we are cygwin.
- if is_pypy:
- py_executable_dlls = [("libpypy-c.dll", "libpypy_d-c.dll")]
- else:
- py_executable_dlls = [
- ("python%s.dll" % (sys.version_info[0]), "python%s_d.dll" % (sys.version_info[0])),
- (
- "python{}{}.dll".format(sys.version_info[0], sys.version_info[1]),
- "python{}{}_d.dll".format(sys.version_info[0], sys.version_info[1]),
- ),
- ]
-
- for py_executable_dll, py_executable_dll_d in py_executable_dlls:
- pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)
- pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)
- pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d)
- if os.path.exists(pythondll):
- logger.info("Also created %s" % py_executable_dll)
- shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll))
- if os.path.exists(pythondll_d):
- logger.info("Also created %s" % py_executable_dll_d)
- shutil.copyfile(pythondll_d, pythondll_d_dest)
- elif os.path.exists(pythondll_d_dest):
- logger.info("Removed %s as the source does not exist" % pythondll_d_dest)
- os.unlink(pythondll_d_dest)
- if is_pypy:
- # make a symlink python --> pypy-c
- python_executable = os.path.join(os.path.dirname(py_executable), "python")
- if sys.platform in ("win32", "cygwin"):
- python_executable += ".exe"
- logger.info("Also created executable %s" % python_executable)
- copyfile(py_executable, python_executable, symlink)
-
- if is_win:
- for name in ["libexpat.dll", "libeay32.dll", "ssleay32.dll", "sqlite3.dll", "tcl85.dll", "tk85.dll"]:
- src = join(prefix, name)
- if os.path.exists(src):
- copyfile(src, join(bin_dir, name), symlink)
-
- for d in sys.path:
- if d.endswith("lib_pypy"):
- break
- else:
- logger.fatal("Could not find lib_pypy in sys.path")
- raise SystemExit(3)
- logger.info("Copying lib_pypy")
- copyfile(d, os.path.join(home_dir, "lib_pypy"), symlink)
-
- if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
- secondary_exe = os.path.join(os.path.dirname(py_executable), expected_exe)
- py_executable_ext = os.path.splitext(py_executable)[1]
- if py_executable_ext.lower() == ".exe":
- # python2.4 gives an extension of '.4' :P
- secondary_exe += py_executable_ext
- if os.path.exists(secondary_exe):
- logger.warn(
- "Not overwriting existing {} script {} (you must use {})".format(
- expected_exe, secondary_exe, py_executable
- )
- )
- else:
- logger.notify("Also creating executable in %s" % secondary_exe)
- shutil.copyfile(sys.executable, secondary_exe)
- make_exe(secondary_exe)
-
- if ".framework" in prefix:
- if "Python.framework" in prefix:
- logger.debug("MacOSX Python framework detected")
- # Make sure we use the embedded interpreter inside
- # the framework, even if sys.executable points to
- # the stub executable in ${sys.prefix}/bin
- # See http://groups.google.com/group/python-virtualenv/
- # browse_thread/thread/17cab2f85da75951
- original_python = os.path.join(prefix, "Resources/Python.app/Contents/MacOS/Python")
- if "EPD" in prefix:
- logger.debug("EPD framework detected")
- original_python = os.path.join(prefix, "bin/python")
- shutil.copy(original_python, py_executable)
-
- # Copy the framework's dylib into the virtual
- # environment
- virtual_lib = os.path.join(home_dir, ".Python")
-
- if os.path.exists(virtual_lib):
- os.unlink(virtual_lib)
- copyfile(os.path.join(prefix, "Python"), virtual_lib, symlink)
-
- # And then change the install_name of the copied python executable
- try:
- mach_o_change(py_executable, os.path.join(prefix, "Python"), "@executable_path/../.Python")
- except Exception:
- e = sys.exc_info()[1]
- logger.warn("Could not call mach_o_change: %s. " "Trying to call install_name_tool instead." % e)
- try:
- call_subprocess(
- [
- "install_name_tool",
- "-change",
- os.path.join(prefix, "Python"),
- "@executable_path/../.Python",
- py_executable,
- ]
- )
- except Exception:
- logger.fatal("Could not call install_name_tool -- you must " "have Apple's development tools installed")
- raise
-
- if not is_win:
- # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist
- py_exe_version_major = "python%s" % sys.version_info[0]
- py_exe_version_major_minor = "python{}.{}".format(sys.version_info[0], sys.version_info[1])
- py_exe_no_version = "python"
- required_symlinks = [py_exe_no_version, py_exe_version_major, py_exe_version_major_minor]
-
- py_executable_base = os.path.basename(py_executable)
-
- if py_executable_base in required_symlinks:
- # Don't try to symlink to yourself.
- required_symlinks.remove(py_executable_base)
-
- for pth in required_symlinks:
- full_pth = join(bin_dir, pth)
- if os.path.exists(full_pth):
- os.unlink(full_pth)
- if symlink:
- os.symlink(py_executable_base, full_pth)
- else:
- copyfile(py_executable, full_pth, symlink)
-
- cmd = [
- py_executable,
- "-c",
- "import sys;out=sys.stdout;" 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))',
- ]
- logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
- try:
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
- proc_stdout, proc_stderr = proc.communicate()
- except OSError:
- e = sys.exc_info()[1]
- if e.errno == errno.EACCES:
- logger.fatal("ERROR: The executable {} could not be run: {}".format(py_executable, e))
- sys.exit(100)
- else:
- raise e
-
- proc_stdout = proc_stdout.strip().decode("utf-8")
- proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
- norm_home_dir = os.path.normcase(os.path.abspath(home_dir))
- if hasattr(norm_home_dir, "decode"):
- norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())
- if proc_stdout != norm_home_dir:
- logger.fatal("ERROR: The executable %s is not functioning" % py_executable)
- logger.fatal("ERROR: It thinks sys.prefix is {!r} (should be {!r})".format(proc_stdout, norm_home_dir))
- logger.fatal("ERROR: virtualenv is not compatible with this system or executable")
- if is_win:
- logger.fatal(
- "Note: some Windows users have reported this error when they "
- 'installed Python for "Only this user" or have multiple '
- "versions of Python installed. Copying the appropriate "
- "PythonXX.dll to the virtualenv Scripts/ directory may fix "
- "this problem."
- )
- sys.exit(100)
- else:
- logger.info("Got sys.prefix result: %r" % proc_stdout)
-
- pydistutils = os.path.expanduser("~/.pydistutils.cfg")
- if os.path.exists(pydistutils):
- logger.notify("Please make sure you remove any previous custom paths from " "your %s file." % pydistutils)
- # FIXME: really this should be calculated earlier
-
- fix_local_scheme(home_dir, symlink)
-
- if site_packages:
- if os.path.exists(site_packages_filename):
- logger.info("Deleting %s" % site_packages_filename)
- os.unlink(site_packages_filename)
-
- return py_executable
-
-
- def install_activate(home_dir, bin_dir, prompt=None):
- if is_win or is_jython and os._name == "nt":
- files = {"activate.bat": ACTIVATE_BAT, "deactivate.bat": DEACTIVATE_BAT, "activate.ps1": ACTIVATE_PS}
-
- # MSYS needs paths of the form /c/path/to/file
- drive, tail = os.path.splitdrive(home_dir.replace(os.sep, "/"))
- home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail)
-
- # Run-time conditional enables (basic) Cygwin compatibility
- home_dir_sh = """$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '{}'; else echo '{}'; fi;)""".format(
- home_dir, home_dir_msys
- )
- files["activate"] = ACTIVATE_SH.replace("__VIRTUAL_ENV__", home_dir_sh)
-
- else:
- files = {"activate": ACTIVATE_SH}
-
- # suppling activate.fish in addition to, not instead of, the
- # bash script support.
- files["activate.fish"] = ACTIVATE_FISH
-
- # same for csh/tcsh support...
- files["activate.csh"] = ACTIVATE_CSH
-
- # same for powershell
- files["activate.ps1"] = ACTIVATE_PS
-
- files["activate_this.py"] = ACTIVATE_THIS
-
- install_files(home_dir, bin_dir, prompt, files)
-
-
- def install_files(home_dir, bin_dir, prompt, files):
- if hasattr(home_dir, "decode"):
- home_dir = home_dir.decode(sys.getfilesystemencoding())
- vname = os.path.basename(home_dir)
- for name, content in files.items():
- content = content.replace("__VIRTUAL_PROMPT__", prompt or "")
- content = content.replace("__VIRTUAL_WINPROMPT__", prompt or "(%s)" % vname)
- content = content.replace("__VIRTUAL_ENV__", home_dir)
- content = content.replace("__VIRTUAL_NAME__", vname)
- content = content.replace("__BIN_NAME__", os.path.basename(bin_dir))
- content = content.replace("__PATH_SEP__", os.pathsep)
- writefile(os.path.join(bin_dir, name), content)
-
-
- def install_python_config(home_dir, bin_dir, prompt=None):
- if sys.platform == "win32" or is_jython and os._name == "nt":
- files = {}
- else:
- files = {"python-config": PYTHON_CONFIG}
- install_files(home_dir, bin_dir, prompt, files)
- for name, _ in files.items():
- make_exe(os.path.join(bin_dir, name))
-
-
- def install_distutils(home_dir):
- distutils_path = change_prefix(distutils.__path__[0], home_dir)
- mkdir(distutils_path)
- # FIXME: maybe this prefix setting should only be put in place if
- # there's a local distutils.cfg with a prefix setting?
- home_dir = os.path.abspath(home_dir)
- # FIXME: this is breaking things, removing for now:
- # distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
- writefile(os.path.join(distutils_path, "__init__.py"), DISTUTILS_INIT)
- writefile(os.path.join(distutils_path, "distutils.cfg"), DISTUTILS_CFG, overwrite=False)
-
-
- def fix_local_scheme(home_dir, symlink=True):
- """
- Platforms that use the "posix_local" install scheme (like Ubuntu with
- Python 2.7) need to be given an additional "local" location, sigh.
- """
- try:
- import sysconfig
- except ImportError:
- pass
- else:
- if sysconfig._get_default_scheme() == "posix_local":
- local_path = os.path.join(home_dir, "local")
- if not os.path.exists(local_path):
- os.mkdir(local_path)
- for subdir_name in os.listdir(home_dir):
- if subdir_name == "local":
- continue
- copyfile(
- os.path.abspath(os.path.join(home_dir, subdir_name)),
- os.path.join(local_path, subdir_name),
- symlink,
- )
-
-
- def fix_lib64(lib_dir, symlink=True):
- """
- Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
- instead of lib/pythonX.Y. If this is such a platform we'll just create a
- symlink so lib64 points to lib
- """
- # PyPy's library path scheme is not affected by this.
- # Return early or we will die on the following assert.
- if is_pypy:
- logger.debug("PyPy detected, skipping lib64 symlinking")
- return
- # Check we have a lib64 library path
- if not [p for p in distutils.sysconfig.get_config_vars().values() if isinstance(p, basestring) and "lib64" in p]:
- return
-
- logger.debug("This system uses lib64; symlinking lib64 to lib")
-
- assert os.path.basename(lib_dir) == "python%s" % sys.version[:3], "Unexpected python lib dir: %r" % lib_dir
- lib_parent = os.path.dirname(lib_dir)
- top_level = os.path.dirname(lib_parent)
- lib_dir = os.path.join(top_level, "lib")
- lib64_link = os.path.join(top_level, "lib64")
- assert os.path.basename(lib_parent) == "lib", "Unexpected parent dir: %r" % lib_parent
- if os.path.lexists(lib64_link):
- return
- if symlink:
- os.symlink(lib_dir, lib64_link)
- else:
- copyfile(lib_dir, lib64_link)
-
-
- def resolve_interpreter(exe):
- """
- If the executable given isn't an absolute path, search $PATH for the interpreter
- """
- # If the "executable" is a version number, get the installed executable for
- # that version
- orig_exe = exe
- python_versions = get_installed_pythons()
- if exe in python_versions:
- exe = python_versions[exe]
-
- if os.path.abspath(exe) != exe:
- exe = distutils.spawn.find_executable(exe) or exe
- if not os.path.exists(exe):
- logger.fatal("The path {} (from --python={}) does not exist".format(exe, orig_exe))
- raise SystemExit(3)
- if not is_executable(exe):
- logger.fatal("The path {} (from --python={}) is not an executable file".format(exe, orig_exe))
- raise SystemExit(3)
- return exe
-
-
- def is_executable(exe):
- """Checks a file is executable"""
- return os.path.isfile(exe) and os.access(exe, os.X_OK)
-
-
- # Relocating the environment:
- def make_environment_relocatable(home_dir):
- """
- Makes the already-existing environment use relative paths, and takes out
- the #!-based environment selection in scripts.
- """
- home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
- activate_this = os.path.join(bin_dir, "activate_this.py")
- if not os.path.exists(activate_this):
- logger.fatal(
- "The environment doesn't have a file %s -- please re-run virtualenv "
- "on this environment to update it" % activate_this
- )
- fixup_scripts(home_dir, bin_dir)
- fixup_pth_and_egg_link(home_dir)
- # FIXME: need to fix up distutils.cfg
-
-
- OK_ABS_SCRIPTS = [
- "python",
- "python%s" % sys.version[:3],
- "activate",
- "activate.bat",
- "activate_this.py",
- "activate.fish",
- "activate.csh",
- ]
-
-
- def fixup_scripts(home_dir, bin_dir):
- if is_win:
- new_shebang_args = ("%s /c" % os.path.normcase(os.environ.get("COMSPEC", "cmd.exe")), "", ".exe")
- else:
- new_shebang_args = ("/usr/bin/env", sys.version[:3], "")
-
- # This is what we expect at the top of scripts:
- shebang = "#!%s" % os.path.normcase(os.path.join(os.path.abspath(bin_dir), "python%s" % new_shebang_args[2]))
- # This is what we'll put:
- new_shebang = "#!%s python%s%s" % new_shebang_args
-
- for filename in os.listdir(bin_dir):
- filename = os.path.join(bin_dir, filename)
- if not os.path.isfile(filename):
- # ignore subdirs, e.g. .svn ones.
- continue
- lines = None
- with open(filename, "rb") as f:
- try:
- lines = f.read().decode("utf-8").splitlines()
- except UnicodeDecodeError:
- # This is probably a binary program instead
- # of a script, so just ignore it.
- continue
- if not lines:
- logger.warn("Script %s is an empty file" % filename)
- continue
-
- old_shebang = lines[0].strip()
- old_shebang = old_shebang[0:2] + os.path.normcase(old_shebang[2:])
-
- if not old_shebang.startswith(shebang):
- if os.path.basename(filename) in OK_ABS_SCRIPTS:
- logger.debug("Cannot make script %s relative" % filename)
- elif lines[0].strip() == new_shebang:
- logger.info("Script %s has already been made relative" % filename)
- else:
- logger.warn(
- "Script %s cannot be made relative (it's not a normal script that starts with %s)"
- % (filename, shebang)
- )
- continue
- logger.notify("Making script %s relative" % filename)
- script = relative_script([new_shebang] + lines[1:])
- with open(filename, "wb") as f:
- f.write("\n".join(script).encode("utf-8"))
-
-
- def relative_script(lines):
- "Return a script that'll work in a relocatable environment."
- activate = (
- "import os; "
- "activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); "
- "exec(compile(open(activate_this).read(), activate_this, 'exec'), dict(__file__=activate_this)); "
- "del os, activate_this"
- )
- # Find the last future statement in the script. If we insert the activation
- # line before a future statement, Python will raise a SyntaxError.
- activate_at = None
- for idx, line in reversed(list(enumerate(lines))):
- if line.split()[:3] == ["from", "__future__", "import"]:
- activate_at = idx + 1
- break
- if activate_at is None:
- # Activate after the shebang.
- activate_at = 1
- return lines[:activate_at] + ["", activate, ""] + lines[activate_at:]
-
-
- def fixup_pth_and_egg_link(home_dir, sys_path=None):
- """Makes .pth and .egg-link files use relative paths"""
- home_dir = os.path.normcase(os.path.abspath(home_dir))
- if sys_path is None:
- sys_path = sys.path
- for path in sys_path:
- if not path:
- path = "."
- if not os.path.isdir(path):
- continue
- path = os.path.normcase(os.path.abspath(path))
- if not path.startswith(home_dir):
- logger.debug("Skipping system (non-environment) directory %s" % path)
- continue
- for filename in os.listdir(path):
- filename = os.path.join(path, filename)
- if filename.endswith(".pth"):
- if not os.access(filename, os.W_OK):
- logger.warn("Cannot write .pth file %s, skipping" % filename)
- else:
- fixup_pth_file(filename)
- if filename.endswith(".egg-link"):
- if not os.access(filename, os.W_OK):
- logger.warn("Cannot write .egg-link file %s, skipping" % filename)
- else:
- fixup_egg_link(filename)
-
-
- def fixup_pth_file(filename):
- lines = []
- prev_lines = []
- with open(filename) as f:
- prev_lines = f.readlines()
- for line in prev_lines:
- line = line.strip()
- if not line or line.startswith("#") or line.startswith("import ") or os.path.abspath(line) != line:
- lines.append(line)
- else:
- new_value = make_relative_path(filename, line)
- if line != new_value:
- logger.debug("Rewriting path {} as {} (in {})".format(line, new_value, filename))
- lines.append(new_value)
- if lines == prev_lines:
- logger.info("No changes to .pth file %s" % filename)
- return
- logger.notify("Making paths in .pth file %s relative" % filename)
- with open(filename, "w") as f:
- f.write("\n".join(lines) + "\n")
-
-
- def fixup_egg_link(filename):
- with open(filename) as f:
- link = f.readline().strip()
- if os.path.abspath(link) != link:
- logger.debug("Link in %s already relative" % filename)
- return
- new_link = make_relative_path(filename, link)
- logger.notify("Rewriting link {} in {} as {}".format(link, filename, new_link))
- with open(filename, "w") as f:
- f.write(new_link)
-
-
- def make_relative_path(source, dest, dest_is_directory=True):
- """
- Make a filename relative, where the filename is dest, and it is
- being referred to from the filename source.
-
- >>> make_relative_path('/usr/share/something/a-file.pth',
- ... '/usr/share/another-place/src/Directory')
- '../another-place/src/Directory'
- >>> make_relative_path('/usr/share/something/a-file.pth',
- ... '/home/user/src/Directory')
- '../../../home/user/src/Directory'
- >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
- './'
- """
- source = os.path.dirname(source)
- if not dest_is_directory:
- dest_filename = os.path.basename(dest)
- dest = os.path.dirname(dest)
- dest = os.path.normpath(os.path.abspath(dest))
- source = os.path.normpath(os.path.abspath(source))
- dest_parts = dest.strip(os.path.sep).split(os.path.sep)
- source_parts = source.strip(os.path.sep).split(os.path.sep)
- while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
- dest_parts.pop(0)
- source_parts.pop(0)
- full_parts = [".."] * len(source_parts) + dest_parts
- if not dest_is_directory:
- full_parts.append(dest_filename)
- if not full_parts:
- # Special case for the current directory (otherwise it'd be '')
- return "./"
- return os.path.sep.join(full_parts)
-
-
- # Bootstrap script creation:
- def create_bootstrap_script(extra_text, python_version=""):
- """
- Creates a bootstrap script, which is like this script but with
- extend_parser, adjust_options, and after_install hooks.
-
- This returns a string that (written to disk of course) can be used
- as a bootstrap script with your own customizations. The script
- will be the standard virtualenv.py script, with your extra text
- added (your extra text should be Python code).
-
- If you include these functions, they will be called:
-
- ``extend_parser(optparse_parser)``:
- You can add or remove options from the parser here.
-
- ``adjust_options(options, args)``:
- You can change options here, or change the args (if you accept
- different kinds of arguments, be sure you modify ``args`` so it is
- only ``[DEST_DIR]``).
-
- ``after_install(options, home_dir)``:
-
- After everything is installed, this function is called. This
- is probably the function you are most likely to use. An
- example would be::
-
- def after_install(options, home_dir):
- subprocess.call([join(home_dir, 'bin', 'easy_install'),
- 'MyPackage'])
- subprocess.call([join(home_dir, 'bin', 'my-package-script'),
- 'setup', home_dir])
-
- This example immediately installs a package, and runs a setup
- script from that package.
-
- If you provide something like ``python_version='2.5'`` then the
- script will start with ``#!/usr/bin/env python2.5`` instead of
- ``#!/usr/bin/env python``. You can use this when the script must
- be run with a particular Python version.
- """
- filename = __file__
- if filename.endswith(".pyc"):
- filename = filename[:-1]
- with codecs.open(filename, "r", encoding="utf-8") as f:
- content = f.read()
- py_exe = "python%s" % python_version
- content = ("#!/usr/bin/env %s\n" % py_exe) + "# WARNING: This file is generated\n" + content
- return content.replace("##EXT" "END##", extra_text)
-
-
- # EXTEND
- def convert(s):
- b = base64.b64decode(s.encode("ascii"))
- return zlib.decompress(b).decode("utf-8")
-
-
- # file site.py
- SITE_PY = convert(
- """
- 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
- AfPVUFM=
- """
- )
-
- # file activate.sh
- ACTIVATE_SH = convert(
- """
- eJytVd9v2kAMfs9fYQLq2m4MscdNVKMqEkgtVIQxbeuUHolpTgsXdHehpT/+9/mSEBJS2MOaB0ji
- z77P9menDpOAK5jzEGERKw0zhFihD/dcB2CrKJYewoyLFvM0XzGNNpzOZbSAGVPBqVWHdRSDx4SI
- NMhYANfgc4meDteW5ePGC45P4MkCumKhUENzDsu1H3lw1vJx1RJxGMKns6O2lWDqINGgotAHFCsu
- I7FAoWHFJGezEFWGqsEvaD5C42naHb93X+A3+elYCgVaxgh8DmQAys9HL2SS0mIaWBgm7mTN/O3G
- kzu6vHCng/HkW/fSve5O+hTOpnhfQAcoEry5jKVjNypoO0fgwzKSOgHm79KUK06Jfc7/RebHpD8a
- 9kdXvT2UcnuFWG6p0stNB0mWUUQ1q3uiGRVEMfXHR03dTuQATPjwqIIPcB9wL4CArRAY/ZHJixYL
- Y9YBtcAoLQtFevOoI9QaHcEdMSAB0d08kuZhyUiSmav6CPCdVBnFOjNrLu6yMCWgKRA0TInBC5i4
- QwX3JG/mm581GKnSsSSxJTFHf9MAKr8w5T/vOv1mUurn5/zlT6fvTntjZzAaNl9rQ5JkU5KIc0GX
- inagwU57T2eddqWlTrvaS6d9sImZeUMkhWysveF0m37NcGub9Dpgi0j4qGiOzATjDr06OBjOYQOo
- 7RBoGtNm9Denv1i0LVI7lxJDXLHSSBeWRflsyyqw7diuW3h0XdvK6lBMyaoMG1UyHdTsoYBuue75
- YOgOu1c91/2cwYpznPPeDoQpGL2xSm09NKp7BsvQ2hnT3aMs07lUnskpxewvBk73/LLnXo9HV9eT
- ijB3hWBO2ygoiWg/bKuZxqCCQq0DD3vkWIVvI2KosIw+vqW1gIItEG5KJb+xb09g65ktwYKgTc51
- uGJ/EFQs0ayEWLCQM5V9N4g+1+8UbXOJzF8bqhKtIqIwicWvzNFROZJlpfD8A7Vc044R0FxkcezG
- VzsV75usvTdYef+57v5n1b225qhXfwEmxHEs
- """
- )
-
- # file activate.fish
- ACTIVATE_FISH = convert(
- """
- eJyFVlFv2zYQftevuMoOnBS1g70WGIZ08RADSRw4boBhGGhGOsUcKFIjKbUu9uN7lCyJsrVWDxZE
- fnf38e6+oyew3QsLmZAIeWkdvCKUFlP6EeoNdlaXJkF4FeqaJ05U3OEiE3a/g/dfhNsLBRxMqZQH
- +3W4hL1zxcfra/9l9yjlItE5XIFFa4VW7xfRBG41KO28IQgHqTCYOHlYRFFWKoqiFaTYhoN5CrPl
- V8JVwriSS1QV5DpF4CoFg640CpwGt0dyanIugRDCaJWjcotZBPRMCGjRgZZpuAsVN4K/SrQ1SmTg
- kHIwVxBP2fr+lr2sNtvPN/fs6WZ7F9cY/3hP87ev4FfhHDjEIYwDUKXRz6L+ub1bP96tH5Yjsbu9
- Uwbdxo95DGE/YPPH6vmOPW3WD09btn5Zbjar24DPBJ7JO1eAeeEOIHVCBdhNffVZW01WcEcdQ0Xi
- UuovdakM5roiqM5gV4MLo8nDrm281tYS891ieBQJ5+6jgNHScItBu8zsSYymc6zTBmsy2og3objs
- 44ThIbAdAyTAqK9YgPqZBZ5ZjNZqLPPDah3RbVGXjy/DKsZTbt6qv375O4Z3v8JMaZXSsim9tnA2
- KKLM5u3eu3HOxSHVyfhWL9eOX81xAp+V5yiMQYkVDyW3iAKRD5lFUdvmwckgZiz4ZCzuYWcSg2kt
- tIFS42lgfs3Yp9Uje7x5WJKnI7zju5v2+tj5bNLiImreMP8XTtQzTiNQ6BgeQy91trrp12e6OLg9
- LczzZg3qejboTqnfhidjt6vnm0/3y2PnxMcB+LsuDnWzJyUVgwoxlEQXm5NYTrvzKMBBz4ftftbN
- A/ioGqjleIUDQlPruCvtB8i0CW0sobi/Jmwh+YFujLNx4MM3xq2TcBw8NSR1hcYIujfIa0Xv9LcA
- s8r8jfQB/vF3YGGwoBTX5MLbQvEc+9jhpOw78yhX1k/IuoxGKJfB7MJe2NkoHC7pLCzRks7eXGNX
- nQeUFv/H3eWFvYLZiDFcvtIQ9IyH3REHbtsp0qRgMzIQu3R2NsleQ4z+Op72WY/hP2j+KXTA0QE3
- nFutYMbG3AnpuuO/AygvqEs=
- """
- )
-
- # file activate.csh
- ACTIVATE_CSH = convert(
- """
- eJx9k9tq20AQhu/3Kf7IJm5N4vRarts6caCBxAnBCZSmLCtpXC1IK2e1svFNn72zklzkA9WFkOb0
- z34708Mi1SWWOiPkVekQEaqSEmy0SxGURWVjQqTNlYqdXitHo7hMAwyXtsjBn8OR6OFHUSFWxhQO
- tjLQDom2FLts6703ljgvQbTFTK11QphpXGeq1Pic1IYk+vY7VzobxUX+ZSRESQ6GNpk2NBm8iYEQ
- KtOqREK7LjBwxN32v8rH+5l8vXtevEzv5dN08R1nE3zC+Tm4CJk1alvQP4oL3wMfVRkvduQdw1Kq
- ynSMkzrPjw9Pi64SVsxj5SaHQnXgf6Rq/7hx+W53jtv5aysdvJ2Fw8BrBaYwCZts5SFQW/OITMe6
- 2iZFzPR6eKm1tbWU0VoZh7WyWkUZlSPRyd1XqC/ioCsEUnZ+pQya6zoiyChazGL/JjrZ4fuVlNd3
- czmfPtxKGf7L4Ecv8aGj1ZBiuZpE8BEuJSPAj1fn8tKonDDBqRxBWUkng/e6cV6aTKKXHtlNUWWJ
- 3wdtoDyZS20c2ZoV+SLaFiYn4y44mGM2qY5TXoOSLtBvxgG8WhUTXfIgJ1CG14qw8XXNwHFWrCxB
- RUXl/HHaGeK47Ubx5ngCPHmt9eDEJ8aIiTex/hh1cseAyR8Mg367VWwYdiuG+4RaSebzs7+jFb7/
- Qqd+g6mF1Uz2LnK3rfX08dulhcFl3vwL0SyW+At+C2qe
- """
- )
-
- # file activate.bat
- ACTIVATE_BAT = convert(
- """
- eJx9Ul9LhEAQfxf8DoOclI/dYyFkaCmcq4gZQTBUrincuZFbff12T133TM+nnd35/Zvxlr7XDFhV
- mUZHOVhFlOWP3g4DUriIWoVomYZpNBWUtGpaWgImO191pFkSpzlcmgaI70jVX7n2Qp8tuByg+46O
- CMHbMq64T+nmlJt082D1T44muCDk2prgEHF4mdI9RaS/QwSt3zSyIAaftRccvqVTBziD1x/WlPD5
- xd729NDBb8Nr4DU9QNMKsJeH9pkhPedhQsIkDuCDCa6A+NF9IevVFAohkqizdHetg/tkWvPoftWJ
- MCqnOxv7/x7Np6yv9P2Ker5dmX8yNyCkkWnbZy3N5LarczlqL8htx2EM9rQ/2H5BvIsIEi8OEG8U
- +g8CsNTr
- """
- )
-
- # file deactivate.bat
- DEACTIVATE_BAT = convert(
- """
- eJyFkN0KgkAUhO8X9h0GQapXCIQEDQX/EBO6kso1F9KN3Or1201Si6JzN+fMGT5mxQ61gKgqSijp
- mETup9nGDgo3yi29S90QjmhnEteOYb6AFNjdBC9xvoj9iTUd7lzWkDVrwFuYiZ15JiW8QiskSlbx
- lpUo4sApXtlJGodJhqNQWW7k+Ou831ACNZrC6BeW+eXPNEbfl7OiXr6H/oHZZl4ceXHoToG0nuIM
- pk+k4fAba/wd0Pr4P2CqyLeOlJ4iKfkJo6v/iaH9YzfPMEoeMG2RUA==
- """
- )
-
- # file activate.ps1
- ACTIVATE_PS = convert(
- """
- eJylWemSo1h2/t8R/Q6amopxd8hdQoC2ctQPdpAAiV1gOzLYxCI2sQom5sn8w4/kV/AFZVZmZVVP
- j8cZoYwU957vnnPuWb5D/s9//fefZ2oYVbNLlPiztKnqmePPvLyeVXlTur43u5R5OjvlSvhvsz5v
- Zq6dZWC1bLJZVP/8059nXlT6bp30n2ZkPqsB1OfZp9mnhe3WUWvX/qeiWv7807iR5s4C9XnmJr6d
- zZpi1mRNBfBbu6w+/fzTx8oto6L+rLKc8nTCVHb2ZfYx7aOszV27jvLsU9q7eZramfepsOvwVQLH
- FOqJ5GQgUBVJVP82Ls9+Kf0qT1r/8e3Dx6+4i0+fPvw6++1kl35Wv6IAgCcRE6hvUT5+Bf+N9+3L
- aMilydxRn1mQ5I6dfPb8F1Nnv8z+veqi2g3/c/ZRzDPSr+qyGRf92a9/HWVn4Ce6gH01WHqcAMyP
- bCfxPz8defJJ52RVw/iHA36d/fUhMv589LP284tffl/oVaD00xyY/7J19uG7vR9mv1VuXvjPljxE
- //Y7er6Y/fkpT7ynNirrxk6eChAcRf1O069bn1e/vHn0A+nvVI5qP3097z9+V+QbVSf/vFhHifq3
- Ko0QYMO7y30nMvstme74R+p8t9Uvy7y0H5FQgdzJQAq4eVZHWeP/yJN/+i4i3ir455niJ5eZ97z+
- pz/wyWvMfT3qb48ka7LKr2dRWfqJ39pZ/TW+qp9/ehOpv2V55r0qM8p+fGvel9fIByvvjQerb75O
- ws/J8H0Qf3mN3Gek58cf3sMunp5wTpyS8An8jNueFOr09PRhNn8LMrrzT99dHlBVwXCeejrJR+Gk
- fvXu+3T9Ufj+dfbhw+jDb6P3Rzu/fBfdPz7lBfjtDWOeN7NnRelfovusHmulP3ObcixDs8f+f505
- TQ2Kb/Yv4HdUuXbpgSL76RWkK0Ec/BbmoEp/+OXjL38Yy7/+Ovsw3bXfJVHmvwL95R9JydeoUjgG
- GID7QTQGe5DZdVP6MyfJ3eu4LHCc4mPm/pBbXNi6Iia5RA6e2SpBUKlGYBJ1JwZsjwdaSQYCwQQa
- JjBXhogqBpMkfMQIYhfsUwJjwC2BlL6uTc9ltNsHHIlJGIbj2GUg68DQKk4t3StUmcWlFeURAwso
- 7P1HIKiOkEz60KEkFuY0hkmasip9vFMCZDhqXXi+wPGJCK3hMmL0pzQIgnUNbGJckiBwOgqwjsOx
- gMP3JCbiwfUWXiNm10E4gKIxEt8JUjWeQeqSxIwYVLffqyRlCLjEYEuNIkJB1BA5dDOZdGAoUFn5
- ysdUKRDXx/pdiDRYj73zPuEouRgxLDiBTKMLJFjvPSZJbUMMPUYLNDjJnDRprIEqBMKd5LG7ELzF
- H2Wm1vxVLmmdCMe9s5w7yL7w2GvHhq4okO5dIDlIiLlOUCXYGJ+pr8+mux2fxwQekxQvYA998VAg
- FK270zGm4YGo41iukroImec9JMG7mqPukEWg98OATbY89lQql4iJiei9peCUbXiFx9AVR4kJ0Luw
- 0iQ2z3LC0WJhwavCSd37kcTgUXbCwASVX749Q6zMszhwJBdo7L5wDLr3FXzvZHLipsvEYpLJXyq8
- v1mGCI0YQAYH94pz8ft7pEBcHEH8bbFxnQgOY8xifXTkuVjz0xvmnPbL/YgBkVshGQLj4JToxUwc
- WY/bkCXrS0iLa1m636BTrEp3GQRyR0viYU942upSH3JhJaKmEk96eGtLtFtXsdcLwdWzEER2Ot+y
- CGvkJIRAon68O3FALrgQYW0dWQy75WqXZW1/lyj3OsW6dSn2OHy4XNc2ezOQfaa0sj8/65bSXEid
- 8BdtfWcUqjsQtlhWvLsrnFzLTY5A8n4wcm3EUK31au5CLFrY8tbd+odFSuyWaIrnaxHypNUSXjhX
- xbN9c2faUsHUxiJcGAv66kiyilTEiFHUNa8nXJxdGxMtd/OhvYVqforv7oU0qcv8TG515ordEn+L
- 2dtQmgvLG+NJMdb72+PgTHfbaMdu0035jecoh69B3cB8rSM7kFMypGISu8AxrcM6Cl8M2HGMCVba
- gkqwpUBcTHpgktmx0rT/iOMmRYv4kYQIy+FDnjG2mwMfBygasOLhhgj4doxjj+skU8BtjKZQfsTY
- 3G9XiW4SGk5ZQcghmzpJkr3pBRJiCGKsRxqNAx1wkur4AavxICjxgKJxye2w3AxHDJuVIZfMWx7x
- EK9fDSDGe48VB4dYxSA3Wxe2BhOmGhPZQwJdTXqwnawJNNft11gyYuTEkeGMEPJYbM33O4DkNu4j
- vwcX7hoTxD+PiKkLiyGfir1DYllOGAGHmuF4/ogx6QCDNeLv6lAJHINN/lQwyldxRGA1hugr5uFT
- UH8dDcEkDhcYs+MDkzt0Jo5LGgtqq8Glf1/HEYNH8NZhkthXVp0FMETsW4wD8w9gwEnjMXrvGPrV
- NmjIesaiJHNvchaHmQ4qBeBeMInEAgwXaIwhDIJRMIaZU9zUX0hJJukrrU6+oMTWUXDSYejB7bGe
- o/HeNpbg3GugGCvIOu9ry5CLqR5Ru8hO9SlvPQJXQd1qbGOVva9b7vCD3jDWFNCD3EzgMUS3RwwR
- PQLIBJXU1ZGqrX51wns8qpGcjW5SEeiUlG9IVq7iM7liF1yvRm0hRFfb9uU71+5WI4Zjyx4a5por
- dGSM7rmYQAxsR+cirSNLRUhiyrLXa2YrSxThCQqoCAFIxmZ5luaudrhPcUoiVM0zjEszcSzwG0pq
- YS5PNuiypKrePXfc2S37ux8Jjgarp2hzRvzE6STBRfd0skcnn/Y7OsSHxsKXpA5XIhyVjO4QCLNY
- zhXYy09kzC8Jm0o62V6o0O16g9v2dNeCssdyoiimGkQf9Khb9TljEvNhydh+ZRjRaenTB4yHOm7D
- BUrLDxrSL/Vi01amfT/q+M2qfYdWDZmd4uMcExVdlhKeBTXkIYgE6hO3SrsA9MjNeb+7NytvLeuG
- gKonWau8OUlaBc6mu7Qa2mgXjBg67cAWs7nJ8plQbn2FzpuFyOMn5xwt0kWiQZB7JCU1IRZ+08XX
- HSvVcnmWFsOtwvfKerJlP/d5plvejpd4zup4srCk4pLz1w2XG4kstTK/rDZ5VFL27WRpnGEugvJ8
- 25XrmDxgBTLVIMs7SMXpCIbsoL4lGnrZLEausA/L0t1t0/JopLpwWOANLWMXaZWTmpDpKWBXAy/E
- h8uUt65uLCLB79BlfwmDg9MVlyFFeLxcWu28oPDADYx1nsm8gmXImRUgX6yHOXa9s+tSvqynu4VT
- M+QpiuHtgt3KS0zAchR3dPpoyavr2RWILu8AUVqCfsmyNgbyjgKxzlHNM0caMb7lSf93DjH545lH
- /LMcYsR44RH/LIeYeuUzj5g4BI6eSZW6CyrgTQO1FAYJRGU+Phuen0GiGnTiEvjI7O6gs/mvPAhS
- 6UFDAc9aidGStUkPta4FaiOhrEHJSaS07i2fBFySklXqJGDQoyaPfBFUYykF9ZBJGkHaduRjL0t1
- FgFqV2Ub6Bu/CiqpFaGTrgq3x4XJp0ZytQygl4pd3tYsQqIMKn3eC+HV876x3qXOAHpyxI1nTTzo
- leuDuithZBBwJ3DHIAZyAvwNjnVPPoabnrjJTrcFdrUW1LXXcOa+SGCziaa6fkm3lsczUJMIzuIq
- 8chFNjeVFpunPtsp61N4uyV0JuYMu28dR/YBlyJ2CieZ6ZGKKWzEKG324mwES1tCYnxENZj0mMaN
- 4aE5rmrzfoiGaDjuachHe1my9HuhMV57NRZzho8J8TDVU36Tci1iLT07uJMH1rTUDcqeIwXVaa1j
- 6eUVWRPdRYBbMFt7Kbp2vEDp9DlOCKnFEaY6cbo9puw0iSU31xNaRlfEoY1Yu0NbsTZNGtOP3oLt
- 8MxPtXTvozHChRZbQtfl3CeZbUiyk0/19hTwey6nYgKNBPq6YowqWA1wFlwhnm+QvSXU7pWtsizF
- T6x02NpIXmiitw09QdxPsR4cu0Ms1fDeUhjAcCiaOOjkLYbo1MtI4XTp+jktynWBC8myGjZbT6ND
- pcwEwGvFc3mbehRaMnOYzo/nJE2XpbPG6LqIscO1YkFPdE9XmDwxRrFYVgY+9zTpqiDBMe3oob/5
- anMuJn9AcXPzkAi7H5n7UpdpaamzPH9BsEFHuyTG7QZec/O62UTnu1/pjat4lSc18A6JOxe+iiPG
- /QDve5bILXYu931ddgp067b1phSOzVXbBd1pm4ICtk4DI9G1Iym4rKrxsRIRVN321mLiY/bF7WLN
- qVHZp9wsbaza4EJ7uxZU4rzRNv7czQqDQSuOPWWtrtrDrky3co9fuXtNE1MtzCSEznIpAP1wjwUC
- jmFMHARHD9Q+MlXHuRbwJ1mgsBgDdRKdOB05ctUODBEdN91tQGLNg2dpE28Fs2T0hj+SWGceJl4E
- qIsI5k1aevs9J6eerWLeg/uiFB1ImtETQckZ+Za7tG26XJiqxPmCtsvcbcc+uHOM40FH55gGUehp
- xJD2SdVQleUMVd4cyTjCXOhWuqCWc+ELDwR/m8A2gh7zOcQmPvjCBR+8kCPGOQlw8eaNDWBON6M/
- 5L/MrpruxRBXfIZfrRiD3mHkf4QB6tGjN7zhaQ8sAt91b/kl1wV+3u3v5nfz8TgbP+vxw/l4mvnl
- G94mcm6fhcB8N4d7MD1wTDJM/RbRE4vAQxMWWzeVx74TeMwWfMLkbY/RUxrUZvnlvN4600sbzPwT
- pzP0xmOFwIHNhxz9TZ/COfaFR3eBm+oAhwb8WAP7VxXoWZMtDsI9ZJmJLzcWo1+B3NLNcMD5tQD0
- hWDk1C5zL0xjFYMe2loRDtnAnhFzxPCNpLF6vBvPBritmd5BL6Uh29g1bo92gdW9mYXGOGBOAuEa
- L/pOMfbQ+W1PLhwYDaSzDs7a9fZZXglgbgNxZFvUqAvovUwyngd6jzT1W+Df3k1pYEeSgL4Vuimw
- lUlqIAt8TQUaDKZOduQCD2zuek+AnhXH0A24C+Fxt8uRHzzrzv0DvkU7MZjy5oIT2+n9B69iZU6k
- wR41k69x+Ttz1TjTmQNXj3PVYy571I9IehOTEkVdVHwjkO6rHwcMD6M691i5O0bb1oHFwX2DP93t
- S/4gegTOn2JKiHbgGYh9MAeC6vMWjwhj+SueaSQT5+ezh90uIo76gRloF1vj9343eAYH4ukeuojQ
- j2sWozVf51RCmGra9G4rkFwBvzHMH8xt/O/MQ4/6QWFhOVD6euhyqj7EGS2HRBV30am/6kW+oqLe
- 32x0fwstS4mM5EOgEERkrAOEvfnexJOPta1U65USw0UKXOLb6EGGVIrgXYdQg8qz2VsH35f9uTNw
- ybAoW19TOLRKuO5S7tDTcnqtSRc6igzXxp07Toohc0I+oCv+6BIiu1Jvt43OqAR2WEXCpm7Zjk7A
- XJHMubVO8XAaF/Q0z1WNHJNHvWwXu1u3sGHY3O/kjbkkoVZTKoS7WXf4IGi2SZ42LJwq8n1/hDOM
- lCy8LqMJI1D7C4kkpr6EhYSLVoTU+YhErMmyvCjCCUGilWEvjvQ+kuCNcbqnimvqYXTLh4JLaRUd
- MU6gH+YR3u7kw9kL1NSilicREqVVzBDYoIH6LtwBR8dBvqrgI7zjmBOn+/+8sxzfV44Yf/DOEhVI
- 8+WdZfttTZ5ib8p9IQKdIE1qEKsrjno/++MnMy1A3kuBBI0zh4KOMwWuVEdQs21cIiYMn8RMPMjH
- vkJhJocA24HNeUccMCIA6YHloFfjVwYMe4zCOQgpUXtsoIQXmSlOH3LgYfft+2ipupMxJrzD18c8
- eYs3cX7gUxyXdaaDaFKJbC5Ctp5R+7KGBYvdqVx/9055fBepALsILmuP1jQje7ZID85lXZcpTVoH
- IY/7O6LFB4G4iTGYNJ3mYEK3c0cTCyoBd7pUwj1M4JbjNWXvHad8kdYuJ0EHmToSXXpe3HF0xyU8
- y2p3MaSuerthGQ2hDhh92XF4vTPLTRxdI3nnxlx1YQ8TL3Tja37Y85sA3vZUwfNXtl76ObK5gMF9
- l5AGZa+sG6Kt+vOc685hqeHpMtyeSwhB6FCd3lvqVNEow5pna6fkF0Owz4hhD9thXO9z028914jE
- 8+WSV3uWtpWLSZJOJFYnmWQXS7tNnRFjFS82eHja4i5uy2u62Na0IzKca7As48Y3XshUF+2WiLNx
- 0IIM++JGJbiNzhMi7by23Y0YTO+ZtRychi3D+jmeH2IEMvFEGGTuQps2RzMcgWIRolHna8Pu1LuZ
- h7rDpAsDOiQoP+kh75d0F+ku76rHvReInAe3Untw53EtlrEbrJTTLoTbBYHa6n1b9+66phD1eArh
- y87ZklMdU+aKo2Plvmj2t/Kk3kkyPy4lMVYD3vV007dIal4uxNhmrLUrKN7WcxDKZpAoJheQ03iP
- f8/UTro4JqLuSEdaljdrcm6JwcnVVpFoIU7aShIXrG0F3wmsVnDUQvGJq5jsTF+/LhdTLWRojQ9E
- QU4584Qe+LbZ9Um4YhokbMmVLobsek4nZ0zs6B7aNOdrtWrobXoBE5VOZLk3zab3q0jc5+tTVWIr
- CxQqtDi7qZkJ2W6TFaeFtKPYvdF9+fL6LyUq877/h9L/AoalQfY=
- """
- )
-
- # file distutils-init.py
- DISTUTILS_INIT = convert(
- """
- eJytV21v5DQQ/u5fMaRCJLANcHxBlVYI7g504nSgU7+gqorcxNk1zdrB9m679+uZsfPivGyPD0Sq
- 5PWMZ8bPPDPjykOrjQN5aJkMS237lT0PyydulFQ7y9gV6LbUlQBpQWkHHE7SuCNvhDrBQVfHRmzA
- angSUHIFR4uaDpyGWqoK3F6AdVUjH9DQO2+bK/cF3OIBbR5BK2jP7XmDimj/cLQOHgT6CIZxlzsw
- wspKWJCKzKEdtHbdnt1eq29RT9ZSVNfP+Tn/BJU0onTanIfL+dgZQ4HiBwFbvG7ecrfPux0SWXd0
- srEF7Ucaf2up0pl6GgzmRVHLRhRFtoFkMJBkTNbDcaXNgRbp1EEG20UQ6eLMYD+7YYBfn4+cFmly
- i7BGaRg8QMvLR75DBB18aYG3reDGUjYQ1YAfWMKh0SV3EtHnNmyerROH0dBPeBfRWBG8Fz7yosil
- ssK49LsNzC8FV8iOf/gN/Prjq+/9ISN4U4yRbYlzeaN5VYTkpkkxXmFUTDbwQSsx97CBNEER/ZGd
- P3//rXjz7uPb17d/fPwry7zDK3it27O/jhGNOCHREAdn5MPRCetVnDmHG4VbGXGSFlEoCgxvGm8e
- S/0R8VyK1sHPvcW3xmgzWmu5tR1YJ2EuWx2EjNVGR5BDR1na2FBCSq1quaN7SYuCG/soW8aGKzxw
- KyzGonasC+0DZjaKalTAOHBBtYxQlnt4OMqmKsSzg5GcUGlh1VcOHpV+gj3+IWt2wnk8seJsVFze
- zp6K9wmLXD9ZuKai33NTUXUESpEKUtDoY9cHvG9R0dXy1ohaPmeMCsb/brirkfxUHAka/eFVEi4x
- xSgv9eHAVZWPN+hQGzeQ0RqXwwbzdsoG8zNqpROVbExjJWrqXLyRn0ShW6oRm1rR1JEOfRQ37uaI
- jOHmjCnGOsMWRtydatK3VN3C3f1ETTRoEvmmLHbIUqSLI5soodl/c7HYy23bSNe3GyvajLEXjUQV
- P2mLlDNP7ZBILMz3SJGkq8T+m4Ccr8PKXkjzanKHH10fCQbmuxFDthBx4SryQquOlfaGMYqWhlYR
- Cs93YEKR1PI30oa6x8jzhRbDMRKIM92PmVP7QtjCqpsOi45ZCHWYVlgMrbbyORnzjQPW+DPdPEvy
- 9hwBV++S0K2G5r16aPXMXGuR8T7ZE8U4aq8uLYnSqdIYC5Y5NgscNjiPGgwi9cAsy4t0cqEq+yRx
- IC4iXikBbwhpedAnkdLxjE1FNA9Vla6Eb4Q7GhXUWHgTfCbliM8KDWJ6jS18yjFsqkV4vhRSlVSm
- vWI+FXWsGsSzkyk1zcK2osQnULnFEg352VIP6uBBHMPmsjd1+959XMsxHstwp057l1jF7FKYOPMq
- XfphuDTXC9klDGJ4ijk8M3vYuC6hSQ/QF9BE8RJNasQVjjSSXkQ3VgJqWf8j3IuopjF9FnzUuQx+
- JFwHf4ZmMUezt9eJTzyMnImpSLYKfyRPv+ZmZztgPT6dxRU/ne6Qg5ceEPRhvDTN1lradIg1fogN
- 56YTeQiK3qaly3y6k/fvfsGHaOL/N8KONihN29OwfdcfuMdo+rjwicftIz6NqDfyphmOzh8FUQjU
- OmchoHvC5YLn/jHq19/AXef8fuqdzMaUHI4sSBblY4VlK1J2kRsLnsW8+Rc/zwIT
- """
- )
-
- # file distutils.cfg
- DISTUTILS_CFG = convert(
- """
- eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
- xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
- 9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
- """
- )
-
- # file activate_this.py
- ACTIVATE_THIS = convert(
- """
- eJyNU8Fu2zAMvesrCA1FbSxzhvUWIIcOGLDDNvTQyxAEhmLTiVZZMiTFif9+pFwnbtFiM2BbFJ8e
- +ShSSvl1gGPQdg94xqrRBrN40KHk1QJqXcWsTEZZri+OPIfBHeGkjRGqirpXEYG90Gsfj8qg7YFe
- 7Z1t0cZCiEf2VsrCDike1nA6oE0s7TFE3gJy4lmHyMk8DPHgLGgb0Xce6bsA66KIB5zH2Gm77BJU
- SCmFiH5YCaBnylngucIuwi/V4jfvnR/dXmkKeB8C+qidTZ4sefiRv6e0/NGOuox+wmuFbjsVD8vo
- lpP4kkFFN9y+Ltn7yDyXKWAudNs5H8GFaRV0xMt6CEI4U5culMwFawIWz7Ut9hgz+XD/+F0uQMpc
- XF2bcXs74vlkUWtvqQzZZKtd4P8lWbrVjxM4YMfGNa7YKarY+2T/JiehDcspOqNi43wL6zXIk7Z3
- X+R4K6ybglVPao9hFuuP0zbj+CTyh96xVoZ+mqAkHE3A/ycxI8nYOTdBwk1KrEcfqBs2q7vtGyGo
- DfuSYNM1GGrVLOkhOxeC8YWqa/5TNbIXieSCkR6VKYmn0WciSGeTIa5L2uckxQf46XoeKpqLuqZ5
- IbY2QHRpq6Ebpo5pksHxV8LiaZ7dZiuoxukUTdGrZMdK0XUkN80VQ17oW12GYc5bqK5DW2d8LL8g
- JlqS11LOz95pd7P6zE04pxF/AX70hVA=
- """
- )
-
- # file python-config
- PYTHON_CONFIG = convert(
- """
- eJyNVV1P2zAUfc+v8ODBiSABxlulTipbO6p1LWqBgVhlhcZpPYUkctzSivHfd6+dpGloGH2Ja/ue
- e+65Hz78xNhtf3x90xmw7vCWsRPGLvpDNuz87MKfdKMWSWxZ4ilNpCLZJiuWc66SVFUOZkkcirll
- rfxIBAzOMtImDzSVPBRrekwoX/OZu/0r4lm0DHiG60g86u8sjPw5rCyy86NRkB8QuuBRSqfAKESn
- 3orLTCQxE3GYkC9tYp8fk89OSwNsmXgizrhUtnumeSgeo5GbLUMk49Rv+2nK48Cm/qMwfp333J2/
- dVcAGE0CIQHBsgIeEr4Wij0LtWDLzJ9ze5YEvH2WI6CHTAVcSu9ZCsXtgxu81CIvp6/k4eXsdfo7
- PvDCRD75yi41QitfzlcPp1OI7i/1/iQitqnr0iMgQ+A6wa+IKwwdxyk9IiXNAzgquTFU8NIxAVjM
- osm1Zz526e+shQ4hKRVci69nPC3Kw4NQEmkQ65E7OodxorSvxjvpBjQHDmWFIQ1mlmzlS5vedseT
- /mgIEsMJ7Lxz2bLAF9M5xeLEhdbHxpWOw0GdkJApMVBRF1y+a0z3c9WZPAXGFcFrJgCIB+024uad
- 0CrzmEoRa3Ub4swNIHPGf7QDV+2uj2OiFWsChgCwjKqN6rp5izpbH6Wc1O1TclQTP/XVwi6anTr1
- 1sbubjZLI1+VptPSdCfwnFBrB1jvebrTA9uUhU2/9gad7xPqeFkaQcnnLbCViZK8d7R1kxzFrIJV
- 8EaLYmKYpvGVkig+3C5HCXbM1jGCGekiM2pRCVPyRyXYdPf6kcbWEQ36F5V4Gq9N7icNNw+JHwRE
- LTgxRXACpvnQv/PuT0xCCAywY/K4hE6Now2qDwaSE5FB+1agsoUveYDepS83qFcF1NufvULD3fTl
- g6Hgf7WBt6lzMeiyyWVn3P1WVbwaczHmTzE9A5SyItTVgFYyvs/L/fXlaNgbw8v3azT+0eikVlWD
- /vBHbzQumP23uBCjsYdrL9OWARwxs/nuLOzeXbPJTa/Xv6sUmQir5pC1YRLz3eA+CD8Z0XpcW8v9
- MZWF36ryyXXf3yBIz6nzqz8Muyz0m5Qj7OexfYo/Ph3LqvkHUg7AuA==
- """
- )
-
- MH_MAGIC = 0xFEEDFACE
- MH_CIGAM = 0xCEFAEDFE
- MH_MAGIC_64 = 0xFEEDFACF
- MH_CIGAM_64 = 0xCFFAEDFE
- FAT_MAGIC = 0xCAFEBABE
- BIG_ENDIAN = ">"
- LITTLE_ENDIAN = "<"
- LC_LOAD_DYLIB = 0xC
- maxint = majver == 3 and getattr(sys, "maxsize") or getattr(sys, "maxint")
-
-
- class fileview(object):
- """
- A proxy for file-like objects that exposes a given view of a file.
- Modified from macholib.
- """
-
- def __init__(self, fileobj, start=0, size=maxint):
- if isinstance(fileobj, fileview):
- self._fileobj = fileobj._fileobj
- else:
- self._fileobj = fileobj
- self._start = start
- self._end = start + size
- self._pos = 0
-
- def __repr__(self):
- return "<fileview [%d, %d] %r>" % (self._start, self._end, self._fileobj)
-
- def tell(self):
- return self._pos
-
- def _checkwindow(self, seekto, op):
- if not (self._start <= seekto <= self._end):
- raise IOError("%s to offset %d is outside window [%d, %d]" % (op, seekto, self._start, self._end))
-
- def seek(self, offset, whence=0):
- seekto = offset
- if whence == os.SEEK_SET:
- seekto += self._start
- elif whence == os.SEEK_CUR:
- seekto += self._start + self._pos
- elif whence == os.SEEK_END:
- seekto += self._end
- else:
- raise IOError("Invalid whence argument to seek: {!r}".format(whence))
- self._checkwindow(seekto, "seek")
- self._fileobj.seek(seekto)
- self._pos = seekto - self._start
-
- def write(self, bytes):
- here = self._start + self._pos
- self._checkwindow(here, "write")
- self._checkwindow(here + len(bytes), "write")
- self._fileobj.seek(here, os.SEEK_SET)
- self._fileobj.write(bytes)
- self._pos += len(bytes)
-
- def read(self, size=maxint):
- assert size >= 0
- here = self._start + self._pos
- self._checkwindow(here, "read")
- size = min(size, self._end - here)
- self._fileobj.seek(here, os.SEEK_SET)
- bytes = self._fileobj.read(size)
- self._pos += len(bytes)
- return bytes
-
-
- def read_data(file, endian, num=1):
- """
- Read a given number of 32-bits unsigned integers from the given file
- with the given endianness.
- """
- res = struct.unpack(endian + "L" * num, file.read(num * 4))
- if len(res) == 1:
- return res[0]
- return res
-
-
- def mach_o_change(path, what, value):
- """
- Replace a given name (what) in any LC_LOAD_DYLIB command found in
- the given binary with a new name (value), provided it's shorter.
- """
-
- def do_macho(file, bits, endian):
- # Read Mach-O header (the magic number is assumed read by the caller)
- cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6)
- # 64-bits header has one more field.
- if bits == 64:
- read_data(file, endian)
- # The header is followed by ncmds commands
- for _ in range(ncmds):
- where = file.tell()
- # Read command header
- cmd, cmdsize = read_data(file, endian, 2)
- if cmd == LC_LOAD_DYLIB:
- # The first data field in LC_LOAD_DYLIB commands is the
- # offset of the name, starting from the beginning of the
- # command.
- name_offset = read_data(file, endian)
- file.seek(where + name_offset, os.SEEK_SET)
- # Read the NUL terminated string
- load = file.read(cmdsize - name_offset).decode()
- load = load[: load.index("\0")]
- # If the string is what is being replaced, overwrite it.
- if load == what:
- file.seek(where + name_offset, os.SEEK_SET)
- file.write(value.encode() + "\0".encode())
- # Seek to the next command
- file.seek(where + cmdsize, os.SEEK_SET)
-
- def do_file(file, offset=0, size=maxint):
- file = fileview(file, offset, size)
- # Read magic number
- magic = read_data(file, BIG_ENDIAN)
- if magic == FAT_MAGIC:
- # Fat binaries contain nfat_arch Mach-O binaries
- nfat_arch = read_data(file, BIG_ENDIAN)
- for _ in range(nfat_arch):
- # Read arch header
- cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5)
- do_file(file, offset, size)
- elif magic == MH_MAGIC:
- do_macho(file, 32, BIG_ENDIAN)
- elif magic == MH_CIGAM:
- do_macho(file, 32, LITTLE_ENDIAN)
- elif magic == MH_MAGIC_64:
- do_macho(file, 64, BIG_ENDIAN)
- elif magic == MH_CIGAM_64:
- do_macho(file, 64, LITTLE_ENDIAN)
-
- assert len(what) >= len(value)
-
- with open(path, "r+b") as f:
- do_file(f)
-
-
- if __name__ == "__main__":
- main()
-
- # TODO:
- # Copy python.exe.manifest
- # Monkeypatch distutils.sysconfig
|