virtualenv3.py :  » Development » PyObjC » trunk » pyobjc » build-support » virtualenv3-src » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » PyObjC 
PyObjC » trunk » pyobjc » build support » virtualenv3 src » virtualenv3.py
#!/usr/bin/env python
"""Create a "virtual" Python installation
"""

import sys
import os
import optparse
import shutil
import logging
import distutils.sysconfig
import zlib
import base64
import subprocess
    
join = os.path.join
py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
is_jython = sys.platform.startswith('java')
expected_exe = is_jython and 'jython' or 'python3'

REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'ntpath', 'genericpath',
                    'fnmatch', 'locale', 'encodings', 'codecs',
                    'stat', 'UserDict', 'readline', 'copy_reg', 'types',
                    're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
                    'lib-dynload', 'config', 'zlib', 'warnings', 'linecache',
                    '_abcoll', 'abc', 'io', '_weakrefset', 'copyreg',
                    'tempfile', 'random', '__future__', 'collections',
                    'keyword', 'tarfile', 'shutil', 'struct', 'copy']

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.WARN, 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
                    sys.stdout.write('\n')
                    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"
            % (msg, self.in_progress))
        if self.level_matches(self.NOTIFY, self._stdout_level()):
            sys.stdout.write(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
                sys.stdout.write('...' + self.in_progress + msg + '\n')
                sys.stdout.flush()
            else:
                sys.stdout.write(msg + '\n')
                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:
            sys.stdout.write('.')
            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 or 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]

    level_for_integer = classmethod(level_for_integer)

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 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 symlink and hasattr(os, 'symlink'):
        logger.info('Symlinking %s', dest)
        os.symlink(os.path.abspath(src), dest)
    else:
        logger.info('Copying to %s', dest)
        if os.path.isdir(src):
            shutil.copytree(src, dest, True)
        else:
            shutil.copy2(src, dest)

def writefile(dest, content, overwrite=True):
    if not os.path.exists(dest):
        logger.info('Writing %s', dest)
        f = open(dest, 'wb')
        f.write(content)
        f.close()
        return
    else:
        f = open(dest, 'rb')
        c = f.read()
        f.close()
        if c != content:
            if not overwrite:
                logger.notify('File %s exists with different content; not overwriting', dest)
                return
            logger.notify('Overwriting %s with new content', dest)
            f = open(dest, 'wb')
            f.write(content)
            f.close()
        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 & 0o7777
        newmode = (oldmode | 0o555) & 0o7777
        os.chmod(fn, newmode)
        logger.info('Changed mode of %s to %s', fn, oct(newmode))

def install_setuptools(py_executable, unzip=False):
    setup_fn = 'setuptools-0.6c9-py%s.egg' % sys.version[:3]
    search_dirs = ['.', os.path.dirname(__file__), join(os.path.dirname(__file__), 'support-files')]
    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:
            search_dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'support-files'))
    for dir in search_dirs:
        if os.path.exists(join(dir, setup_fn)):
            setup_fn = join(dir, setup_fn)
            break
    if is_jython and os._name == 'nt':
        # Jython's .bat sys.executable can't handle a command line
        # argument with newlines
        import tempfile
        fd, ez_setup = tempfile.mkstemp('.py')
        os.write(fd, EZ_SETUP_PY)
        os.close(fd)
        cmd = [py_executable, ez_setup]
    else:
        cmd = [py_executable, '-c', EZ_SETUP_PY]
    if unzip:
        cmd.append('--always-unzip')
    env = {}
    if logger.stdout_level_matches(logger.DEBUG):
        cmd.append('-v')
    if os.path.exists(setup_fn):
        logger.info('Using existing Setuptools egg: %s', setup_fn)
        cmd.append(setup_fn)
        if os.environ.get('PYTHONPATH'):
            env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
        else:
            env['PYTHONPATH'] = setup_fn
    else:
        logger.info('No Setuptools egg found; downloading')
        cmd.extend(['--always-copy', '-U', 'setuptools'])
    logger.start_progress('Installing setuptools...')
    logger.indent += 2
    cwd = None
    if not os.access(os.getcwd(), os.W_OK):
        cwd = '/tmp'
    try:
        call_subprocess(cmd, show_stdout=False,
                        filter_stdout=filter_ez_setup,
                        extra_env=env,
                        cwd=cwd)
    finally:
        logger.indent -= 2
        logger.end_progress()
        if is_jython and os._name == 'nt':
            os.remove(ez_setup)

def filter_ez_setup(line):
    if not line.strip():
        return Logger.DEBUG
    for prefix in ['Reading ', 'Best match', 'Processing setuptools',
                   'Copying setuptools', 'Adding setuptools',
                   'Installing ', 'Installed ']:
        if line.startswith(prefix):
            return Logger.DEBUG
    return Logger.INFO

def main():
    parser = optparse.OptionParser(
        version="1.3.4dev",
        usage="%prog [OPTIONS] DEST_DIR")

    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=python2.5 will use the python2.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.add_option(
        '--no-site-packages',
        dest='no_site_packages',
        action='store_true',
        help="Don't give access to the global site-packages dir to the "
             "virtual environment")

    parser.add_option(
        '--unzip-setuptools',
        dest='unzip_setuptools',
        action='store_true',
        help="Unzip Setuptools when installing it")

    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')

    if 'extend_parser' in globals():
        extend_parser(parser)

    options, args = parser.parse_args()

    global logger

    if 'adjust_options' in globals():
        adjust_options(options, args)

    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]
            os.execvpe(interpreter, [interpreter, file] + sys.argv[1:], env)

    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.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 os.environ.get('PYTHONHOME'):
        if sys.platform == 'win32':
            name = '%PYTHONHOME%'
        else:
            name = '$PYTHONHOME'
        logger.warn('%s is set; this can cause problems creating environments' % name)

    if options.relocatable:
        make_environment_relocatable(home_dir)
        return

    create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
                       unzip_setuptools=options.unzip_setuptools)
    if 'after_install' in globals():
        after_install(options, home_dir)

def call_subprocess(cmd, show_stdout=True,
                    filter_stdout=None, cwd=None,
                    raise_on_returncode=True, extra_env=None):
    cmd_parts = []
    for part in cmd:
        if isinstance(part, bytes):
            part = part.decode('utf-8')
        if len(part) > 40:
            part = part[:30]+"..."+part[-5:]
        if ' ' in part or '\n' in part or '"' in part or "'" in part:
            part = '"%s"' % part.replace('"', '\\"')
        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:
        env = os.environ.copy()
        env.update(extra_env)
    else:
        env = None
    try:
        proc = subprocess.Popen(
            cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
            cwd=cwd, env=env)
    except Exception as e:
        logger.fatal(
            "Error %s while executing command %s" % (e, cmd_desc))
        raise
    all_output = []
    if stdout is not None:
        stdout = proc.stdout
        while 1:
            line = stdout.readline().decode('ascii')
            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()
    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 %s failed with error code %s"
                % (cmd_desc, proc.returncode))
        else:
            logger.warn(
                "Command %s had error code %s"
                % (cmd_desc, proc.returncode))


def create_environment(home_dir, site_packages=True, clear=False,
                       unzip_setuptools=False):
    """
    Creates a new environment in ``home_dir``.

    If ``site_packages`` is true (the default) 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 = install_python(
        home_dir, lib_dir, inc_dir, bin_dir, 
        site_packages=site_packages, clear=clear)

    install_distutils(lib_dir, home_dir)

    install_setuptools(py_executable, unzip=unzip_setuptools)

    install_activate(home_dir, bin_dir)

def path_locations(home_dir):
    """Return the path locations for the environment (where libraries are,
    where scripts go, etc)"""
    # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
    # prefix arg is broken: http://bugs.python.org/issue3386
    if sys.platform == 'win32':
        # Windows has lots of problems with executables with spaces in
        # the name; this function will remove them (using the ~1
        # format):
        mkdir(home_dir)
        if ' ' in home_dir:
            try:
                import win32api
            except ImportError:
                print('Error: the path "%s" has a space in it' % home_dir)
                print('To handle these kinds of paths, the win32api module must be installed:')
                print('  http://sourceforge.net/projects/pywin32/')
                sys.exit(3)
            home_dir = win32api.GetShortPathName(home_dir)
        lib_dir = join(home_dir, 'Lib')
        inc_dir = join(home_dir, 'Include')
        bin_dir = join(home_dir, 'Scripts')
    elif is_jython:
        lib_dir = join(home_dir, 'Lib')
        inc_dir = join(home_dir, 'Include')
        bin_dir = join(home_dir, 'bin')
    else:
        lib_dir = join(home_dir, 'lib', py_version)
        inc_dir = join(home_dir, 'include', py_version)
        bin_dir = join(home_dir, 'bin')
    return home_dir, lib_dir, inc_dir, bin_dir

def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
    """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
    else:
        prefix = sys.prefix
    mkdir(lib_dir)
    fix_lib64(lib_dir)
    stdlib_dirs = [os.path.dirname(os.__file__)]
    if sys.platform == 'win32':
        stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
    elif sys.platform == 'darwin':
        stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
        macosx_framework_name = distutils.sysconfig.get_config_var('PYTHONFRAMEWORK')
        macosx_framework = '/' + macosx_framework_name + '.framework/'

    for stdlib_dir in stdlib_dirs:
        if not os.path.isdir(stdlib_dir):
            continue
        if hasattr(os, 'symlink'):
            logger.info('Symlinking Python bootstrap modules')
        else:
            logger.info('Copying Python bootstrap modules')
        logger.indent += 2
        try:
            for fn in os.listdir(stdlib_dir):
                if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_MODULES:
                    copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
        finally:
            logger.indent -= 2
    mkdir(join(lib_dir, 'site-packages'))
    writefile(join(lib_dir, 'site.py'), SITE_PY)
    writefile(join(lib_dir, 'orig-prefix.txt'), prefix.encode('utf-8'))
    site_packages_filename = join(lib_dir, 'no-global-site-packages.txt')
    if not site_packages:
        writefile(site_packages_filename, b'')
    else:
        if os.path.exists(site_packages_filename):
            logger.info('Deleting %s' % site_packages_filename)
            os.unlink(site_packages_filename)

    stdinc_dir = join(prefix, 'include', py_version)
    if os.path.exists(stdinc_dir):
        copyfile(stdinc_dir, inc_dir)
    else:
        logger.debug('No include dir %s' % stdinc_dir)

    if sys.exec_prefix != prefix:
        if sys.platform == 'win32':
            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)
        for fn in os.listdir(exec_dir):
            copyfile(join(exec_dir, fn), join(lib_dir, fn))
    
    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))
        # 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 sys.platform == 'darwin' and macosx_framework in prefix:
        # The name of the python executable is not quite what
        # we want, rename it.
        py_executable = os.path.join(
                os.path.dirname(py_executable), 'python3')

    logger.notify('New %s executable in %s', expected_exe, py_executable)
    if sys.executable != py_executable:
        ## FIXME: could I just hard link?
        executable = sys.executable
        if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
            # Cygwin misreports sys.executable sometimes
            executable += '.exe'
            py_executable += '.exe'
            logger.info('Executable actually exists in %s' % executable)
        shutil.copyfile(executable, py_executable)
        make_exe(py_executable)
        if sys.platform == 'win32' or sys.platform == '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'))
                
    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 == '.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 %s script %s (you must use %s)'
                        % (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 sys.platform == 'darwin' and macosx_framework in prefix:
        logger.debug('MacOSX Python framework detected')
        
        # Make sure we use the 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
        embedded = os.path.join(prefix, 'Resources/Python.app/Contents/MacOS/Python')
        if not os.path.exists(embedded):
            embedded = os.path.join(prefix, 'Resources/Python.app/Contents/MacOS', macosx_framework_name)
        shutil.copy(
                embedded,
                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, macosx_framework_name),
            virtual_lib)

        if (sys.version_info[0] == 2 and sys.version_info[1] >= 7) or \
            (sys.version_info[0] == 3 and sys.version_info[1] >= 2):
            # Python 2.7 (and later) and Python 3.2 (and later) include
            # a version of pythonw with hooks for virtualenv, use those hooks.
            embedded = os.path.join(home_dir, '.Resources/Python.app/Contents/MacOS', macosx_framework_name)
            if not os.path.exists(os.path.dirname(embedded)):
                os.makedirs(os.path.dirname(embedded))

            os.rename(py_executable, embedded)
            try:
                call_subprocess(
                    ["install_name_tool", "-change",
                     os.path.join(prefix, macosx_framework_name),
                     '@executable_path/../../../../.Python',
                     embedded])
            except:
                logger.fatal(
                    "Could not call install_name_tool -- you must have Apple's development tools installed")
                raise

            shutil.copy(os.path.join(prefix, 'bin/python3'), py_executable)


        # And then change the install_name of the copied python executable
        try:
            call_subprocess(
                ["install_name_tool", "-change",
                 os.path.join(prefix, macosx_framework_name),
                 '@executable_path/../.Python',
                 py_executable])
        except:
            logger.fatal(
                "Could not call install_name_tool -- you must have Apple's development tools installed")
            raise

        # Some tools depend on pythonX.Y being present
        py_executable_version = '.%s' % (
            sys.version_info[1],)
        if not py_executable.endswith(py_executable_version):
            # symlinking pythonX.Y > python
            pth = py_executable + '.%s' % (
                    sys.version_info[1],)
            if os.path.exists(pth):
                os.unlink(pth)
            os.symlink('python3', pth)
        else:
            # reverse symlinking python -> pythonX.Y (with --python)
            pth = join(bin_dir, 'python3')
            if os.path.exists(pth):
                os.unlink(pth)
            os.symlink(os.path.basename(py_executable), pth)

    if sys.platform == 'win32' and ' ' in py_executable:
        # There's a bug with subprocess on Windows when using a first
        # argument that has a space in it.  Instead we have to quote
        # the value:
        py_executable = '"%s"' % py_executable
    cmd = [py_executable, '-c',
           'import sys; sys.stdout.write(sys.prefix)']
    logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    proc_stdout, proc_stderr = proc.communicate()
    proc_stdout = proc_stdout.decode('utf-8').strip()
    proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
    if proc_stdout != os.path.normcase(os.path.abspath(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)'
            % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
        logger.fatal(
            'ERROR: virtualenv is not compatible with this system or executable')
        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
    return py_executable

def install_activate(home_dir, bin_dir):
    if sys.platform == 'win32' or is_jython and os._name == 'nt':
        files = {'activate.bat': ACTIVATE_BAT,
                 'deactivate.bat': DEACTIVATE_BAT}
        if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
            files['activate'] = ACTIVATE_SH
    else:
        files = {'activate': ACTIVATE_SH}
    files['activate_this.py'] = ACTIVATE_THIS
    for name, content in list(files.items()):
        content = content.replace(b'__VIRTUAL_ENV__',
                                  os.path.abspath(home_dir).encode('utf-8'))
        content = content.replace(b'__VIRTUAL_NAME__',
                                  os.path.basename(os.path.abspath(home_dir))
                                  .encode('utf-8'))
        content = content.replace(b'__BIN_NAME__',
                                  os.path.basename(bin_dir).encode('utf-8'))

        writefile(os.path.join(bin_dir, name), content)

def install_distutils(lib_dir, home_dir):
    distutils_path = os.path.join(lib_dir, 'distutils')
    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_lib64(lib_dir):
    """
    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
    """
    if [p for p in list(distutils.sysconfig.get_config_vars().values()) 
        if isinstance(p, str) and 'lib64' in p]:
        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)
        assert os.path.basename(lib_parent) == 'lib', (
            "Unexpected parent dir: %r" % lib_parent)
        copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))

def resolve_interpreter(exe):
    """
    If the executable given isn't an absolute path, search $PATH for the interpreter
    """
    if os.path.abspath(exe) != exe:
        paths = os.environ.get('PATH', '').split(os.pathsep)
        for path in paths:
            if os.path.exists(os.path.join(path, exe)):
                exe = os.path.join(path, exe)
                break
    if not os.path.exists(exe):
        logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
        sys.exit(3)
    return exe

############################################################
## 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.
    """
    activate_this = os.path.join(home_dir, 'bin', '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)
    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']

def fixup_scripts(home_dir):
    # This is what we expect at the top of scripts:
    shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
    # This is what we'll put:
    new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
    activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
    bin_dir = os.path.join(home_dir, 'bin')
    for filename in os.listdir(bin_dir):
        filename = os.path.join(bin_dir, filename)
        f = open(filename, 'rb')
        lines = f.readlines()
        f.close()
        if not lines:
            logger.warn('Script %s is an empty file' % filename)
            continue
        if not lines[0].strip().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)
        lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
        f = open(filename, 'wb')
        f.writelines(lines)
        f.close()

def fixup_pth_and_egg_link(home_dir):
    """Makes .pth and .egg-link files use relative paths"""
    home_dir = os.path.normcase(os.path.abspath(home_dir))
    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 = []
    f = open(filename)
    prev_lines = f.readlines()
    f.close()
    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 %s as %s (in %s)' % (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)
    f = open(filename, 'w')
    f.write('\n'.join(lines) + '\n')
    f.close()

def fixup_egg_link(filename):
    f = open(filename)
    link = f.read().strip()
    f.close()
    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 %s in %s as %s' % (link, filename, new_link))
    f = open(filename, 'w')
    f.write(new_link)
    f.close()

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.4'`` then the
    script will start with ``#!/usr/bin/env python2.4`` 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]
    f = open(filename, 'rb')
    content = f.read()
    f.close()
    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##

##file site.py
SITE_PY = zlib.decompress(base64.b64decode(b"""
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
0b2P0K0N+QJdHZ2F1u43OXpzbdKtlp/8L6y4BuM=
"""))

##file ez_setup.py
EZ_SETUP_PY = zlib.decompress(base64.b64decode(b"""
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
"""))

##file activate.sh
ACTIVATE_SH = zlib.decompress(base64.b64decode(b"""
eJytU11P2zAUffevuKQ8AFqJ+srUh6IhgcTKRFgnjSLXTW4aS6ld2U6zgvbfd50PSD+GNI08JLHv
8fW5557bg4dMWkhljrAsrIM5QmExgVK6DAKrCxMjzKUKRezkWjgM4Cw1eglzYbMz1oONLiAWSmkH
plAgHSTSYOzyDWMJtqfg5BReGNAjU3iEvoLgmN/dfuGTm/uH76Nb/m30cB3AE3wGl6GqkP7x28ND
0FcE/lpp4yrg616hLDrYO1TFU8mqb6+u3Ga6yBNI0BHnqigQKoFnm32CMpNxBplYIwj6UCjWy6UP
u0y4Sq8mFakWizwn3ZyGBd1NMtBfqo1frAQJ2xy15wA/SFtduCbspFo0abaAXgg49rwhzoRaoIWS
miQS/9qAF5yuNWhXxByTHXEvRxHp2df16md0zSdX99HN3fiAyFVpfbMlz9/aFA0OdSka7DWJgHs9
igbvtqgJtxRqSBu9Gk/eiB0RLyIyhEBplaB1pvBGwx1uPYgwT6EFHO3c3veh1qHt1b8ZmbqOS2Mw
p+4rB2thpJjnaLue3r6bsQ7VYcB5Z8l5wBoRuvWwPYuSjLW9m0UHHXJ+eTPm49HXK84vGljX/WxX
TZ/Mt6GSLJiRuVGJJcJ0K+80mFVKEsdd9by1pMjJ2xa9W2FEO4rst5BxM+baSBKlgSNC5tzqIgzL
sjx/RkdmXZ+ToUOrU1cKg6HwGUL26prHDq0ZpTxIcDqbPUFdC+YW306fvFPUaX2AWtqxH/ugsf+A
kf/Pcf/3UW/HnBT5Axjqy2Y=
"""))

##file activate.bat
ACTIVATE_BAT = zlib.decompress(base64.b64decode(b"""
eJx9kMsOgjAQRfdN+g+zoAn8goZEDESJPBpEViSzkFbZ0IX8f+RRaVW0u5mee3PanbjeFSgpKXmI
Hqq4KC9BglFW+YjWhEgJJa2ETvXQCNl2ogFe5CkvwaUEhjPm543vcOdAiacjLxzzJFw6f2bZCsZ0
2YitXPtswawi1zwgC9II0QPD/RELyuOb1jB/Sg0rNhM31Ss4n2I+7ibLb8epQGco2Rja1Fs/zeoa
cR9nWnprJaMspOQJdBR1/g==
"""))

##file deactivate.bat
DEACTIVATE_BAT = zlib.decompress(base64.b64decode(b"""
eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
FlWqXJpcICVYpGzx2OAY4oFsPpCLbjpQCLvZILVcXFaufi5cACHzOrI=
"""))

##file distutils-init.py
DISTUTILS_INIT = zlib.decompress(base64.b64decode(b"""
eJytVk2L5DYQvetXFN0E28msCcltoVkIe1lYcgiBHIbBaGy5Wxm3ZCT1dHd+faokty35Y5PDGmZw
q0pVr56qnizPvTYOtGUyvNn7+HrlRkl1tPBYqLVq5bHnxgoD+/SntKC0Aw7v0rgL74R6h7NuLp14
AqvhKqDmCi5WgHTgNLRSNeBOAqxrOvnKWCON4mcBBwRT9tydymGFTNZdnOxsReuRx99aqnzmnsew
yqpqZSeqqniCbAyTFUy2YxClzZle8jRNAYcFlHyxZ4xffGSAz4Ozkl5yv0TP7k+sNGJmTAU9r9/4
UQB38IMF3vcCgRNBr8iUCgwRLZ2uuZNaAbdh8W6dOE+BPu0KJjorAozKl1BVpVTIgst/foJZdd5N
3ESd615MJHpGU1dkrqqkkg7D9fesKEojeJMXBWOt0REEGNqEFjZMiDocD2Nsv8fiXX2C14vsmkrc
HEyZodHCqszBm9JXOOEfUnIUzteO/YIO0ojaaXMfAp0AybliV+mrhQ/UZSdumlo3IhBGLkiw0Zeh
8Xxy0RCmsjeilTesCPvC/+64a/GMqQcyDPrrL1kgNi2rrPX5zFVTTiUMhU4LeF4aX8cFH6buuLWT
U554DK1ETyNamhTeyX9EpXtqAAu5FV0bOdFDuHG1RGoMN/cK2bE0k79rJVJPepauB3h+SdzYN/2j
vko6h7jD7uiqQOgT7L7iWe2KIgmXVFvO6wvlLcGsU79K+PijChIUAsxXo1M7TEbfmFMaehtaxX5k
jKCTdFWhjf30E3vkVn7Gf0a+XqiMcuHFhsNMV+PDbH1vHmA1SURLmP1qGpaZIi7mN2KtPWYhyD6S
QHFDB5vP4w6w9iO26NgXvuOB7eGvE/caX/OuC6MmzIcL3RKhIKCC2NC2iCHoPk5ar628ZVO/0h5f
/XAz7FCAklp2QcZG3VvdtLpn7rVo40cHJ45FhNq7S0umPHWasKCGoBKhTqOUdwgi9zQuZ5d8SqEa
e5V4qWQzxFmxHOFwHkac9bvIaXvBUhNdJarJV+Ab4S5GBTf2PxoX2Vk2czolo67PRgUVu+rv7qQV
3iA1Bhody9Tkh2M0zvblJMeV7UUtW1kfsPvC4RxI3QZukMSwuFS9Yd0nj9UpJmMJNk36SFmwLZD4
qdHouqqG+V03sq36Y2pmexdMohBvMUlfUptMonHJpHUoonhRknWT2dgJSHS/I9ULVCmm/yAePbaJ
j4zrxM+YnO2diB/M79zflGmoyLZCfWTNf+Tm+NBUz80QbyXL4Dvy/61PEnoQLd3LazqWXsedv47H
fSQ9FkUdCa9FPoKir8XaFf6os69ffvv85Y/Mf96jjI1OqSaNy8+PDS+I5oFrj7fyG35rkR7ipTDu
FN0mApLLGQLMTrRsJMZ00/tP8DzkfkmSU9S4GccdbPPcVvprxco2u2LRYXHH/Avon569
"""))

##file distutils.cfg
DISTUTILS_CFG = zlib.decompress(base64.b64decode(b"""
eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
"""))

##file activate_this.py
ACTIVATE_THIS = zlib.decompress(base64.b64decode(b"""
eJx1UsGOnDAMvecrIlYriDRlKvU20h5aaY+teuilGo1QALO4CwlKAjP8fe1QGGalRoLEefbzs+Mk
Sb7NcvRo3iTcoGqwgyy06As+HWSNVciKaBTFywYoJWc7yit2ndBVwEkHkIzKCV0YdQdmkvShs6YH
E3IhfjFaaSNLoHxQy2sLJrL0ow98JQmEG/rAYn7OobVGogngBgf0P0hjgwgt7HOUaI5DdBVJkggR
3HwSktaqWcCtgiHIH7qHV+esW2CnkRJ+9R5cQGsikkWEV/J7leVGs9TV4TvcO5QOOrTHYI+xeCjY
JR/m9GPDHv2oSZunUokS2A/WBelnvx6tF6LUJO2FjjlH5zU6Q+Kz/9m69LxvSZVSwiOlGnT1rt/A
77j+WDQZ8x9k2mFJetOle88+lc8sJJ/AeerI+fTlQigTfVqJUiXoKaaC3AqmI+KOnivjMLbvBVFU
1JDruuadNGcPmkgiBTnQXUGUDd6IK9JEQ9yPdM96xZP8bieeMRqTuqbxIbbey2DjVUNzRs1rosFS
TsLAdS/0fBGNdTGKhuqD7mUmsFlgGjN2eSj1tM3GnjfXwwCmzjhMbR4rLZXXk+Z/6Hp7Pn2+kJ49
jfgLHgI4Jg==
"""))

if __name__ == '__main__':
    main()

## TODO:
## Copy python.exe.manifest
## Monkeypatch distutils.sysconfig
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.