KanonConductor

changeset 31:ca083cbc2c09

merge centos5-supprot branch.
author chris
date Mon, 28 Mar 2011 03:22:46 +0900
parents 3d1c15c7cefa c6335712741b
children 640e6a9509aa
files kanon-setup pkglist.rhel
diffstat 7 files changed, 1780 insertions(+), 34 deletions(-) [+]
line diff
     1.1 --- a/kanon-setup	Fri Mar 25 00:30:38 2011 +0900
     1.2 +++ b/kanon-setup	Mon Mar 28 03:22:46 2011 +0900
     1.3 @@ -9,8 +9,14 @@
     1.4      APACHE_USER=www-data
     1.5  elif [ -f /etc/redhat-release ]
     1.6  then
     1.7 -    OS='rhel'
     1.8      APACHE_USER=apache
     1.9 +    CHK=`egrep "CentOS release 5|Red Hat Enterprise Linux .* 5" /etc/redhat-release`
    1.10 +    if [ "$CHK" != '' ]
    1.11 +    then
    1.12 +        OS='rhel5'
    1.13 +    else
    1.14 +        OS='rhel6'
    1.15 +    fi
    1.16  else
    1.17      echo "サポートされていないOSです。"
    1.18      echo "現在サポートされいているOSは、"
    1.19 @@ -19,6 +25,7 @@
    1.20      echo "  * Debian GNU/Linux, GNU/kFreeBSD 6.0"
    1.21      echo "  * RedHat Enterprise Linux 6.0"
    1.22      echo "  * Oracle Enterprise Linux 6.0"
    1.23 +    echo "  * CentOS 5.x (Experimental)"
    1.24      echo ""
    1.25      echo "です。"
    1.26      exit
    1.27 @@ -49,23 +56,44 @@
    1.28  fi
    1.29  
    1.30  ### install ubuntu package 
    1.31 -if [ "$OS" = 'debian' ]
    1.32 -then
    1.33 -    apt-get update
    1.34 -    apt-get -y install `cat pkglist.debian`
    1.35 -elif [ "$OS" = 'rhel' ]
    1.36 -then
    1.37 -    yum -y install `cat pkglist.rhel`
    1.38 -fi
    1.39 +case $OS in
    1.40 +    debian)
    1.41 +        apt-get update 
    1.42 +        apt-get -y install `cat pkglist.debian` 
    1.43 +        ;;
    1.44 +    rhel6)
    1.45 +        yum -y install `cat pkglist.rhel6`
    1.46 +        ;;
    1.47 +    rhel5)
    1.48 +        # Add EPEL Repository. For python26, python26-devel, python26-mod_wsgi.
    1.49 +        EPEL_RPM_URL="http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm"
    1.50 +        wget $EPEL_RPM_URL
    1.51 +        rpm -Uvh epel-release-5-4.noarch.rpm
    1.52 +        rm -f epel-release-5-4.noarch.rpm
    1.53 +        yum -y install `cat pkglist.rhel5`
    1.54 +
    1.55 +        # Add Kanon Repository. For Subversion 1.6 with Python26.
    1.56 +        cp -f resource/kanon.repo /etc/yum.repos.d/kanon.repo
    1.57 +        yum -y install subversion-1.6.15 mod_dav_svn-1.6.15
    1.58 +        ;;
    1.59 +    *)
    1.60 +        ;;
    1.61 +esac
    1.62  
    1.63  ### install files
    1.64  cp -fr opt/* /opt
    1.65 -cp -frn etc/* /etc
    1.66 +if [ "$OS" = "rhel5" ]
    1.67 +then
    1.68 +    # FIXME CentOS 5.x では n オプションがないため 強制上書きになってしまう.
    1.69 +    cp -fr etc/* /etc
    1.70 +else
    1.71 +    cp -frn etc/* /etc
    1.72 +fi
    1.73  
    1.74  
    1.75  ### setup configuration
    1.76 -export PYTHONPATH=/opt/kanon/lib/python2.6:/opt/kanon/lib/python2.6/site-packages
    1.77 -cp resource/dot.pydistutils.cfg ~/.pydistutils.cfg
    1.78 +python2.6 resource/virtualenv.py /opt/kanon
    1.79 +source /opt/kanon/bin/activate
    1.80  
    1.81  ## setup sitecustomize for python
    1.82  if [ -f /etc/python2.6/sitecustomize.py ]
    1.83 @@ -77,19 +105,27 @@
    1.84      fi
    1.85  fi
    1.86  
    1.87 -### install python components
    1.88 -easy_install --prefix $KANON_OPT http://svn.edgewall.org/repos/genshi/tags/0.6.0/
    1.89 -easy_install --prefix $KANON_OPT http://ftp.edgewall.com/pub/babel/Babel-0.9.5.zip
    1.90 -easy_install --prefix $KANON_OPT http://www.i-act.co.jp/project/products/downloads/Trac-0.12.2.ja1.zip
    1.91 -easy_install --prefix $KANON_OPT xlrd
    1.92 -easy_install --prefix $KANON_OPT https://github.com/hvr/trac-git-plugin/zipball/v0.12.0.5
    1.93 +
    1.94 +if [ "$OS" = "rhel5" ]
    1.95 +then
    1.96 +    # Install Extra Package for CentOS 5.X
    1.97 +    easy_install "mercurial==1.7.3"
    1.98 +    easy_install bzr
    1.99 +    easy_install pygments
   1.100 +fi
   1.101 +
   1.102 +easy_install http://svn.edgewall.org/repos/genshi/tags/0.6.0/
   1.103 +easy_install http://ftp.edgewall.com/pub/babel/Babel-0.9.5.zip
   1.104 +easy_install http://www.i-act.co.jp/project/products/downloads/Trac-0.12.2.ja1.zip
   1.105 +easy_install xlrd
   1.106 +easy_install https://github.com/hvr/trac-git-plugin/zipball/v0.12.0.5
   1.107  # bzr co lp:trac-bzr /tmp/trac-bzr-install
   1.108  #easy_install --prefix /opt/kanon /tmp/trac-bzr-install
   1.109  #rm -fr /tmp/trac-bzr-install
   1.110  
   1.111  
   1.112  ### install trac plugins
   1.113 -easy_install --prefix $KANON_OPT http://svn.edgewall.com/repos/trac/plugins/0.12/mercurial-plugin 
   1.114 +easy_install http://svn.edgewall.com/repos/trac/plugins/0.12/mercurial-plugin
   1.115  
   1.116  #resource/pluginsディレクトリのプラグインをインストール
   1.117  pushd .
   1.118 @@ -97,8 +133,8 @@
   1.119  cd resource/trac-plugins
   1.120  for i in `ls -1 .`
   1.121  do
   1.122 -    cd $i;python setup.py install --prefix=/opt/kanon
   1.123 -    cd ..   
   1.124 +    cd $i;python setup.py install
   1.125 +    cd ..
   1.126  done
   1.127  cd ../..
   1.128  
   1.129 @@ -109,7 +145,7 @@
   1.130      cd /tmp
   1.131      svn co $i kanon_build
   1.132      cd kanon_build
   1.133 -    python setup.py install --prefix=/opt/kanon
   1.134 +    python setup.py install
   1.135      cd ..
   1.136      rm -fr kanon_build
   1.137  done
   1.138 @@ -117,6 +153,7 @@
   1.139  
   1.140  
   1.141  ### setup apache and restart
   1.142 +<<<<<<< local
   1.143  if [ "$OS" = 'debian' ]
   1.144  then
   1.145      cp resource/trac_hook.py /usr/lib/python2.6/dist-packages/bzrlib/plugins
   1.146 @@ -149,6 +186,53 @@
   1.147      service httpd stop
   1.148      service httpd start
   1.149  fi
   1.150 +=======
   1.151 +case $OS in
   1.152 +    debian)
   1.153 +        cp resource/trac_hook.py /usr/lib/python2.6/dist-packages/bzrlib/plugins
   1.154 +        if [ ! -f /etc/apache2/sites-available/kanon ]
   1.155 +        then
   1.156 +            cp resource/httpd.conf /etc/apache2/sites-available/kanon
   1.157 +        fi
   1.158 +        a2enmod expires
   1.159 +        a2enmod auth_digest
   1.160 +        a2enmod dav_fs
   1.161 +        a2ensite kanon
   1.162 +        service apache2 stop
   1.163 +        service apache2 start
   1.164 +        ;;
   1.165 +    rhel6)
   1.166 +        mkdir -p /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.167 +        cp resource/trac_hook.py /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.168 +        if [ ! -f /etc/httpd/conf.d/kanon.conf ]
   1.169 +        then
   1.170 +            cp resource/httpd.conf /etc/httpd/conf.d/kanon.conf
   1.171 +        fi
   1.172 +        echo 0 > /selinux/enforce
   1.173 +        echo "SELinuxが無効化されました"
   1.174 +        service httpd stop
   1.175 +        service httpd start
   1.176 +        ;;
   1.177 +    rhel5)
   1.178 +        mkdir -p /var/opt/kanon/trac/.egg-cache
   1.179 +        chown $APACHE_USER:$APACHE_USER -R /var/opt/kanon/trac/.egg-cache/
   1.180 +        mkdir -p /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.181 +        cp resource/trac_hook.py /usr/lib/python2.6/site-packages/bzrlib/plugin
   1.182 +        if [ ! -f /etc/httpd/conf.d/kanon.conf ]
   1.183 +        then
   1.184 +            cp resource/httpd.conf /etc/httpd/conf.d/kanon.conf
   1.185 +        fi
   1.186 +        echo 0 > /selinux/enforce
   1.187 +        echo "SELinuxが無効化されました"
   1.188 +        mv /etc/httpd/conf.d/python.conf /etc/httpd/conf.d/python.conf.disabled
   1.189 +        service httpd stop
   1.190 +        service httpd start
   1.191 +        ;;
   1.192 +    *)
   1.193 +        ;;
   1.194 +esac
   1.195 +
   1.196 +>>>>>>> other
   1.197  
   1.198  # データディレクトリが存在しない場合作成
   1.199  if [ ! -d "$KANON_VAR/trac" ]
     2.1 --- a/pkglist.rhel	Fri Mar 25 00:30:38 2011 +0900
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,11 +0,0 @@
     2.4 -httpd
     2.5 -python-setuptools
     2.6 -python-pygments
     2.7 -sqlite
     2.8 -mod_dav_svn
     2.9 -mod_wsgi
    2.10 -subversion
    2.11 -mercurial
    2.12 -bzr
    2.13 -gcc
    2.14 -git
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/pkglist.rhel5	Mon Mar 28 03:22:46 2011 +0900
     3.3 @@ -0,0 +1,6 @@
     3.4 +python26
     3.5 +python26-devel
     3.6 +python26-mod_wsgi
     3.7 +httpd
     3.8 +sqlite
     3.9 +gcc
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/pkglist.rhel6	Mon Mar 28 03:22:46 2011 +0900
     4.3 @@ -0,0 +1,11 @@
     4.4 +httpd
     4.5 +python-setuptools
     4.6 +python-pygments
     4.7 +sqlite
     4.8 +mod_dav_svn
     4.9 +mod_wsgi
    4.10 +subversion
    4.11 +mercurial
    4.12 +bzr
    4.13 +gcc
    4.14 +git
     5.1 --- a/resource/httpd.conf	Fri Mar 25 00:30:38 2011 +0900
     5.2 +++ b/resource/httpd.conf	Mon Mar 28 03:22:46 2011 +0900
     5.3 @@ -24,7 +24,7 @@
     5.4  </Location>
     5.5  
     5.6  # Subversionの設定
     5.7 -<Location "/svn">
     5.8 +<Location "/svn/">
     5.9  	DAV svn
    5.10  	SVNParentPath /var/opt/kanon/svn
    5.11  	SVNListParentPath on
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/resource/kanon.repo	Mon Mar 28 03:22:46 2011 +0900
     6.3 @@ -0,0 +1,5 @@
     6.4 +[kanon]
     6.5 +name = RHEL $releasever - Kanon - chris
     6.6 +baseurl = http://kanon.ultimania.org/pkg/centos5/$basearch
     6.7 +enabled = 1
     6.8 +gpgcheck = 0
     6.9 \ No newline at end of file
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/resource/virtualenv.py	Mon Mar 28 03:22:46 2011 +0900
     7.3 @@ -0,0 +1,1651 @@
     7.4 +#!/usr/bin/env python
     7.5 +"""Create a "virtual" Python installation
     7.6 +"""
     7.7 +
     7.8 +virtualenv_version = "1.5.1"
     7.9 +
    7.10 +import sys
    7.11 +import os
    7.12 +import optparse
    7.13 +import re
    7.14 +import shutil
    7.15 +import logging
    7.16 +import tempfile
    7.17 +import distutils.sysconfig
    7.18 +try:
    7.19 +    import subprocess
    7.20 +except ImportError, e:
    7.21 +    if sys.version_info <= (2, 3):
    7.22 +        print 'ERROR: %s' % e
    7.23 +        print 'ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.'
    7.24 +        print 'If you copy subprocess.py from a newer version of Python this script will probably work'
    7.25 +        sys.exit(101)
    7.26 +    else:
    7.27 +        raise
    7.28 +try:
    7.29 +    set
    7.30 +except NameError:
    7.31 +    from sets import Set as set
    7.32 +
    7.33 +join = os.path.join
    7.34 +py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
    7.35 +
    7.36 +is_jython = sys.platform.startswith('java')
    7.37 +is_pypy = hasattr(sys, 'pypy_version_info')
    7.38 +
    7.39 +if is_pypy:
    7.40 +    expected_exe = 'pypy-c'
    7.41 +elif is_jython:
    7.42 +    expected_exe = 'jython'
    7.43 +else:
    7.44 +    expected_exe = 'python'
    7.45 +
    7.46 +
    7.47 +REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
    7.48 +                    'fnmatch', 'locale', 'encodings', 'codecs',
    7.49 +                    'stat', 'UserDict', 'readline', 'copy_reg', 'types',
    7.50 +                    're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
    7.51 +                    'zlib']
    7.52 +
    7.53 +REQUIRED_FILES = ['lib-dynload', 'config']
    7.54 +
    7.55 +if sys.version_info[:2] >= (2, 6):
    7.56 +    REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
    7.57 +if sys.version_info[:2] >= (2, 7):
    7.58 +    REQUIRED_MODULES.extend(['_weakrefset'])
    7.59 +if sys.version_info[:2] <= (2, 3):
    7.60 +    REQUIRED_MODULES.extend(['sets', '__future__'])
    7.61 +if is_pypy:
    7.62 +    # these are needed to correctly display the exceptions that may happen
    7.63 +    # during the bootstrap
    7.64 +    REQUIRED_MODULES.extend(['traceback', 'linecache'])
    7.65 +
    7.66 +class Logger(object):
    7.67 +
    7.68 +    """
    7.69 +    Logging object for use in command-line script.  Allows ranges of
    7.70 +    levels, to avoid some redundancy of displayed information.
    7.71 +    """
    7.72 +
    7.73 +    DEBUG = logging.DEBUG
    7.74 +    INFO = logging.INFO
    7.75 +    NOTIFY = (logging.INFO+logging.WARN)/2
    7.76 +    WARN = WARNING = logging.WARN
    7.77 +    ERROR = logging.ERROR
    7.78 +    FATAL = logging.FATAL
    7.79 +
    7.80 +    LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
    7.81 +
    7.82 +    def __init__(self, consumers):
    7.83 +        self.consumers = consumers
    7.84 +        self.indent = 0
    7.85 +        self.in_progress = None
    7.86 +        self.in_progress_hanging = False
    7.87 +
    7.88 +    def debug(self, msg, *args, **kw):
    7.89 +        self.log(self.DEBUG, msg, *args, **kw)
    7.90 +    def info(self, msg, *args, **kw):
    7.91 +        self.log(self.INFO, msg, *args, **kw)
    7.92 +    def notify(self, msg, *args, **kw):
    7.93 +        self.log(self.NOTIFY, msg, *args, **kw)
    7.94 +    def warn(self, msg, *args, **kw):
    7.95 +        self.log(self.WARN, msg, *args, **kw)
    7.96 +    def error(self, msg, *args, **kw):
    7.97 +        self.log(self.WARN, msg, *args, **kw)
    7.98 +    def fatal(self, msg, *args, **kw):
    7.99 +        self.log(self.FATAL, msg, *args, **kw)
   7.100 +    def log(self, level, msg, *args, **kw):
   7.101 +        if args:
   7.102 +            if kw:
   7.103 +                raise TypeError(
   7.104 +                    "You may give positional or keyword arguments, not both")
   7.105 +        args = args or kw
   7.106 +        rendered = None
   7.107 +        for consumer_level, consumer in self.consumers:
   7.108 +            if self.level_matches(level, consumer_level):
   7.109 +                if (self.in_progress_hanging
   7.110 +                    and consumer in (sys.stdout, sys.stderr)):
   7.111 +                    self.in_progress_hanging = False
   7.112 +                    sys.stdout.write('\n')
   7.113 +                    sys.stdout.flush()
   7.114 +                if rendered is None:
   7.115 +                    if args:
   7.116 +                        rendered = msg % args
   7.117 +                    else:
   7.118 +                        rendered = msg
   7.119 +                    rendered = ' '*self.indent + rendered
   7.120 +                if hasattr(consumer, 'write'):
   7.121 +                    consumer.write(rendered+'\n')
   7.122 +                else:
   7.123 +                    consumer(rendered)
   7.124 +
   7.125 +    def start_progress(self, msg):
   7.126 +        assert not self.in_progress, (
   7.127 +            "Tried to start_progress(%r) while in_progress %r"
   7.128 +            % (msg, self.in_progress))
   7.129 +        if self.level_matches(self.NOTIFY, self._stdout_level()):
   7.130 +            sys.stdout.write(msg)
   7.131 +            sys.stdout.flush()
   7.132 +            self.in_progress_hanging = True
   7.133 +        else:
   7.134 +            self.in_progress_hanging = False
   7.135 +        self.in_progress = msg
   7.136 +
   7.137 +    def end_progress(self, msg='done.'):
   7.138 +        assert self.in_progress, (
   7.139 +            "Tried to end_progress without start_progress")
   7.140 +        if self.stdout_level_matches(self.NOTIFY):
   7.141 +            if not self.in_progress_hanging:
   7.142 +                # Some message has been printed out since start_progress
   7.143 +                sys.stdout.write('...' + self.in_progress + msg + '\n')
   7.144 +                sys.stdout.flush()
   7.145 +            else:
   7.146 +                sys.stdout.write(msg + '\n')
   7.147 +                sys.stdout.flush()
   7.148 +        self.in_progress = None
   7.149 +        self.in_progress_hanging = False
   7.150 +
   7.151 +    def show_progress(self):
   7.152 +        """If we are in a progress scope, and no log messages have been
   7.153 +        shown, write out another '.'"""
   7.154 +        if self.in_progress_hanging:
   7.155 +            sys.stdout.write('.')
   7.156 +            sys.stdout.flush()
   7.157 +
   7.158 +    def stdout_level_matches(self, level):
   7.159 +        """Returns true if a message at this level will go to stdout"""
   7.160 +        return self.level_matches(level, self._stdout_level())
   7.161 +
   7.162 +    def _stdout_level(self):
   7.163 +        """Returns the level that stdout runs at"""
   7.164 +        for level, consumer in self.consumers:
   7.165 +            if consumer is sys.stdout:
   7.166 +                return level
   7.167 +        return self.FATAL
   7.168 +
   7.169 +    def level_matches(self, level, consumer_level):
   7.170 +        """
   7.171 +        >>> l = Logger()
   7.172 +        >>> l.level_matches(3, 4)
   7.173 +        False
   7.174 +        >>> l.level_matches(3, 2)
   7.175 +        True
   7.176 +        >>> l.level_matches(slice(None, 3), 3)
   7.177 +        False
   7.178 +        >>> l.level_matches(slice(None, 3), 2)
   7.179 +        True
   7.180 +        >>> l.level_matches(slice(1, 3), 1)
   7.181 +        True
   7.182 +        >>> l.level_matches(slice(2, 3), 1)
   7.183 +        False
   7.184 +        """
   7.185 +        if isinstance(level, slice):
   7.186 +            start, stop = level.start, level.stop
   7.187 +            if start is not None and start > consumer_level:
   7.188 +                return False
   7.189 +            if stop is not None or stop <= consumer_level:
   7.190 +                return False
   7.191 +            return True
   7.192 +        else:
   7.193 +            return level >= consumer_level
   7.194 +
   7.195 +    #@classmethod
   7.196 +    def level_for_integer(cls, level):
   7.197 +        levels = cls.LEVELS
   7.198 +        if level < 0:
   7.199 +            return levels[0]
   7.200 +        if level >= len(levels):
   7.201 +            return levels[-1]
   7.202 +        return levels[level]
   7.203 +
   7.204 +    level_for_integer = classmethod(level_for_integer)
   7.205 +
   7.206 +def mkdir(path):
   7.207 +    if not os.path.exists(path):
   7.208 +        logger.info('Creating %s', path)
   7.209 +        os.makedirs(path)
   7.210 +    else:
   7.211 +        logger.info('Directory %s already exists', path)
   7.212 +
   7.213 +def copyfile(src, dest, symlink=True):
   7.214 +    if not os.path.exists(src):
   7.215 +        # Some bad symlink in the src
   7.216 +        logger.warn('Cannot find file %s (bad symlink)', src)
   7.217 +        return
   7.218 +    if os.path.exists(dest):
   7.219 +        logger.debug('File %s already exists', dest)
   7.220 +        return
   7.221 +    if not os.path.exists(os.path.dirname(dest)):
   7.222 +        logger.info('Creating parent directories for %s' % os.path.dirname(dest))
   7.223 +        os.makedirs(os.path.dirname(dest))
   7.224 +    if symlink and hasattr(os, 'symlink'):
   7.225 +        logger.info('Symlinking %s', dest)
   7.226 +        os.symlink(os.path.abspath(src), dest)
   7.227 +    else:
   7.228 +        logger.info('Copying to %s', dest)
   7.229 +        if os.path.isdir(src):
   7.230 +            shutil.copytree(src, dest, True)
   7.231 +        else:
   7.232 +            shutil.copy2(src, dest)
   7.233 +
   7.234 +def writefile(dest, content, overwrite=True):
   7.235 +    if not os.path.exists(dest):
   7.236 +        logger.info('Writing %s', dest)
   7.237 +        f = open(dest, 'wb')
   7.238 +        f.write(content)
   7.239 +        f.close()
   7.240 +        return
   7.241 +    else:
   7.242 +        f = open(dest, 'rb')
   7.243 +        c = f.read()
   7.244 +        f.close()
   7.245 +        if c != content:
   7.246 +            if not overwrite:
   7.247 +                logger.notify('File %s exists with different content; not overwriting', dest)
   7.248 +                return
   7.249 +            logger.notify('Overwriting %s with new content', dest)
   7.250 +            f = open(dest, 'wb')
   7.251 +            f.write(content)
   7.252 +            f.close()
   7.253 +        else:
   7.254 +            logger.info('Content %s already in place', dest)
   7.255 +
   7.256 +def rmtree(dir):
   7.257 +    if os.path.exists(dir):
   7.258 +        logger.notify('Deleting tree %s', dir)
   7.259 +        shutil.rmtree(dir)
   7.260 +    else:
   7.261 +        logger.info('Do not need to delete %s; already gone', dir)
   7.262 +
   7.263 +def make_exe(fn):
   7.264 +    if hasattr(os, 'chmod'):
   7.265 +        oldmode = os.stat(fn).st_mode & 07777
   7.266 +        newmode = (oldmode | 0555) & 07777
   7.267 +        os.chmod(fn, newmode)
   7.268 +        logger.info('Changed mode of %s to %s', fn, oct(newmode))
   7.269 +
   7.270 +def _find_file(filename, dirs):
   7.271 +    for dir in dirs:
   7.272 +        if os.path.exists(join(dir, filename)):
   7.273 +            return join(dir, filename)
   7.274 +    return filename
   7.275 +
   7.276 +def _install_req(py_executable, unzip=False, distribute=False):
   7.277 +    if not distribute:
   7.278 +        setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
   7.279 +        project_name = 'setuptools'
   7.280 +        bootstrap_script = EZ_SETUP_PY
   7.281 +        source = None
   7.282 +    else:
   7.283 +        setup_fn = None
   7.284 +        source = 'distribute-0.6.14.tar.gz'
   7.285 +        project_name = 'distribute'
   7.286 +        bootstrap_script = DISTRIBUTE_SETUP_PY
   7.287 +        try:
   7.288 +            # check if the global Python has distribute installed or plain
   7.289 +            # setuptools
   7.290 +            import pkg_resources
   7.291 +            if not hasattr(pkg_resources, '_distribute'):
   7.292 +                location = os.path.dirname(pkg_resources.__file__)
   7.293 +                logger.notify("A globally installed setuptools was found (in %s)" % location)
   7.294 +                logger.notify("Use the --no-site-packages option to use distribute in "
   7.295 +                              "the virtualenv.")
   7.296 +        except ImportError:
   7.297 +            pass
   7.298 +
   7.299 +    search_dirs = file_search_dirs()
   7.300 +
   7.301 +    if setup_fn is not None:
   7.302 +        setup_fn = _find_file(setup_fn, search_dirs)
   7.303 +
   7.304 +    if source is not None:
   7.305 +        source = _find_file(source, search_dirs)
   7.306 +
   7.307 +    if is_jython and os._name == 'nt':
   7.308 +        # Jython's .bat sys.executable can't handle a command line
   7.309 +        # argument with newlines
   7.310 +        fd, ez_setup = tempfile.mkstemp('.py')
   7.311 +        os.write(fd, bootstrap_script)
   7.312 +        os.close(fd)
   7.313 +        cmd = [py_executable, ez_setup]
   7.314 +    else:
   7.315 +        cmd = [py_executable, '-c', bootstrap_script]
   7.316 +    if unzip:
   7.317 +        cmd.append('--always-unzip')
   7.318 +    env = {}
   7.319 +    remove_from_env = []
   7.320 +    if logger.stdout_level_matches(logger.DEBUG):
   7.321 +        cmd.append('-v')
   7.322 +
   7.323 +    old_chdir = os.getcwd()
   7.324 +    if setup_fn is not None and os.path.exists(setup_fn):
   7.325 +        logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
   7.326 +        cmd.append(setup_fn)
   7.327 +        if os.environ.get('PYTHONPATH'):
   7.328 +            env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
   7.329 +        else:
   7.330 +            env['PYTHONPATH'] = setup_fn
   7.331 +    else:
   7.332 +        # the source is found, let's chdir
   7.333 +        if source is not None and os.path.exists(source):
   7.334 +            os.chdir(os.path.dirname(source))
   7.335 +            # in this case, we want to be sure that PYTHONPATH is unset (not
   7.336 +            # just empty, really unset), else CPython tries to import the
   7.337 +            # site.py that it's in virtualenv_support
   7.338 +            remove_from_env.append('PYTHONPATH')
   7.339 +        else:
   7.340 +            logger.info('No %s egg found; downloading' % project_name)
   7.341 +        cmd.extend(['--always-copy', '-U', project_name])
   7.342 +    logger.start_progress('Installing %s...' % project_name)
   7.343 +    logger.indent += 2
   7.344 +    cwd = None
   7.345 +    if project_name == 'distribute':
   7.346 +        env['DONT_PATCH_SETUPTOOLS'] = 'true'
   7.347 +
   7.348 +    def _filter_ez_setup(line):
   7.349 +        return filter_ez_setup(line, project_name)
   7.350 +
   7.351 +    if not os.access(os.getcwd(), os.W_OK):
   7.352 +        cwd = tempfile.mkdtemp()
   7.353 +        if source is not None and os.path.exists(source):
   7.354 +            # the current working dir is hostile, let's copy the
   7.355 +            # tarball to a temp dir
   7.356 +            target = os.path.join(cwd, os.path.split(source)[-1])
   7.357 +            shutil.copy(source, target)
   7.358 +    try:
   7.359 +        call_subprocess(cmd, show_stdout=False,
   7.360 +                        filter_stdout=_filter_ez_setup,
   7.361 +                        extra_env=env,
   7.362 +                        remove_from_env=remove_from_env,
   7.363 +                        cwd=cwd)
   7.364 +    finally:
   7.365 +        logger.indent -= 2
   7.366 +        logger.end_progress()
   7.367 +        if os.getcwd() != old_chdir:
   7.368 +            os.chdir(old_chdir)
   7.369 +        if is_jython and os._name == 'nt':
   7.370 +            os.remove(ez_setup)
   7.371 +
   7.372 +def file_search_dirs():
   7.373 +    here = os.path.dirname(os.path.abspath(__file__))
   7.374 +    dirs = ['.', here,
   7.375 +            join(here, 'virtualenv_support')]
   7.376 +    if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
   7.377 +        # Probably some boot script; just in case virtualenv is installed...
   7.378 +        try:
   7.379 +            import virtualenv
   7.380 +        except ImportError:
   7.381 +            pass
   7.382 +        else:
   7.383 +            dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
   7.384 +    return [d for d in dirs if os.path.isdir(d)]
   7.385 +
   7.386 +def install_setuptools(py_executable, unzip=False):
   7.387 +    _install_req(py_executable, unzip)
   7.388 +
   7.389 +def install_distribute(py_executable, unzip=False):
   7.390 +    _install_req(py_executable, unzip, distribute=True)
   7.391 +
   7.392 +_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
   7.393 +def install_pip(py_executable):
   7.394 +    filenames = []
   7.395 +    for dir in file_search_dirs():
   7.396 +        filenames.extend([join(dir, fn) for fn in os.listdir(dir)
   7.397 +                          if _pip_re.search(fn)])
   7.398 +    filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
   7.399 +    filenames.sort()
   7.400 +    filenames = [filename for basename, i, filename in filenames]
   7.401 +    if not filenames:
   7.402 +        filename = 'pip'
   7.403 +    else:
   7.404 +        filename = filenames[-1]
   7.405 +    easy_install_script = 'easy_install'
   7.406 +    if sys.platform == 'win32':
   7.407 +        easy_install_script = 'easy_install-script.py'
   7.408 +    cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename]
   7.409 +    if filename == 'pip':
   7.410 +        logger.info('Installing pip from network...')
   7.411 +    else:
   7.412 +        logger.info('Installing %s' % os.path.basename(filename))
   7.413 +    logger.indent += 2
   7.414 +    def _filter_setup(line):
   7.415 +        return filter_ez_setup(line, 'pip')
   7.416 +    try:
   7.417 +        call_subprocess(cmd, show_stdout=False,
   7.418 +                        filter_stdout=_filter_setup)
   7.419 +    finally:
   7.420 +        logger.indent -= 2
   7.421 +
   7.422 +def filter_ez_setup(line, project_name='setuptools'):
   7.423 +    if not line.strip():
   7.424 +        return Logger.DEBUG
   7.425 +    if project_name == 'distribute':
   7.426 +        for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
   7.427 +                       'Scanning', 'Setuptools', 'Egg', 'Already',
   7.428 +                       'running', 'writing', 'reading', 'installing',
   7.429 +                       'creating', 'copying', 'byte-compiling', 'removing',
   7.430 +                       'Processing'):
   7.431 +            if line.startswith(prefix):
   7.432 +                return Logger.DEBUG
   7.433 +        return Logger.DEBUG
   7.434 +    for prefix in ['Reading ', 'Best match', 'Processing setuptools',
   7.435 +                   'Copying setuptools', 'Adding setuptools',
   7.436 +                   'Installing ', 'Installed ']:
   7.437 +        if line.startswith(prefix):
   7.438 +            return Logger.DEBUG
   7.439 +    return Logger.INFO
   7.440 +
   7.441 +def main():
   7.442 +    parser = optparse.OptionParser(
   7.443 +        version=virtualenv_version,
   7.444 +        usage="%prog [OPTIONS] DEST_DIR")
   7.445 +
   7.446 +    parser.add_option(
   7.447 +        '-v', '--verbose',
   7.448 +        action='count',
   7.449 +        dest='verbose',
   7.450 +        default=0,
   7.451 +        help="Increase verbosity")
   7.452 +
   7.453 +    parser.add_option(
   7.454 +        '-q', '--quiet',
   7.455 +        action='count',
   7.456 +        dest='quiet',
   7.457 +        default=0,
   7.458 +        help='Decrease verbosity')
   7.459 +
   7.460 +    parser.add_option(
   7.461 +        '-p', '--python',
   7.462 +        dest='python',
   7.463 +        metavar='PYTHON_EXE',
   7.464 +        help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
   7.465 +        'interpreter to create the new environment.  The default is the interpreter that '
   7.466 +        'virtualenv was installed with (%s)' % sys.executable)
   7.467 +
   7.468 +    parser.add_option(
   7.469 +        '--clear',
   7.470 +        dest='clear',
   7.471 +        action='store_true',
   7.472 +        help="Clear out the non-root install and start from scratch")
   7.473 +
   7.474 +    parser.add_option(
   7.475 +        '--no-site-packages',
   7.476 +        dest='no_site_packages',
   7.477 +        action='store_true',
   7.478 +        help="Don't give access to the global site-packages dir to the "
   7.479 +             "virtual environment")
   7.480 +
   7.481 +    parser.add_option(
   7.482 +        '--unzip-setuptools',
   7.483 +        dest='unzip_setuptools',
   7.484 +        action='store_true',
   7.485 +        help="Unzip Setuptools or Distribute when installing it")
   7.486 +
   7.487 +    parser.add_option(
   7.488 +        '--relocatable',
   7.489 +        dest='relocatable',
   7.490 +        action='store_true',
   7.491 +        help='Make an EXISTING virtualenv environment relocatable.  '
   7.492 +        'This fixes up scripts and makes all .pth files relative')
   7.493 +
   7.494 +    parser.add_option(
   7.495 +        '--distribute',
   7.496 +        dest='use_distribute',
   7.497 +        action='store_true',
   7.498 +        help='Use Distribute instead of Setuptools. Set environ variable '
   7.499 +        'VIRTUALENV_USE_DISTRIBUTE to make it the default ')
   7.500 +
   7.501 +    parser.add_option(
   7.502 +        '--prompt=',
   7.503 +        dest='prompt',
   7.504 +        help='Provides an alternative prompt prefix for this environment')
   7.505 +
   7.506 +    if 'extend_parser' in globals():
   7.507 +        extend_parser(parser)
   7.508 +
   7.509 +    options, args = parser.parse_args()
   7.510 +
   7.511 +    global logger
   7.512 +
   7.513 +    if 'adjust_options' in globals():
   7.514 +        adjust_options(options, args)
   7.515 +
   7.516 +    verbosity = options.verbose - options.quiet
   7.517 +    logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
   7.518 +
   7.519 +    if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
   7.520 +        env = os.environ.copy()
   7.521 +        interpreter = resolve_interpreter(options.python)
   7.522 +        if interpreter == sys.executable:
   7.523 +            logger.warn('Already using interpreter %s' % interpreter)
   7.524 +        else:
   7.525 +            logger.notify('Running virtualenv with interpreter %s' % interpreter)
   7.526 +            env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
   7.527 +            file = __file__
   7.528 +            if file.endswith('.pyc'):
   7.529 +                file = file[:-1]
   7.530 +            popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
   7.531 +            raise SystemExit(popen.wait())
   7.532 +
   7.533 +    if not args:
   7.534 +        print 'You must provide a DEST_DIR'
   7.535 +        parser.print_help()
   7.536 +        sys.exit(2)
   7.537 +    if len(args) > 1:
   7.538 +        print 'There must be only one argument: DEST_DIR (you gave %s)' % (
   7.539 +            ' '.join(args))
   7.540 +        parser.print_help()
   7.541 +        sys.exit(2)
   7.542 +
   7.543 +    home_dir = args[0]
   7.544 +
   7.545 +    if os.environ.get('WORKING_ENV'):
   7.546 +        logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
   7.547 +        logger.fatal('Please deactivate your workingenv, then re-run this script')
   7.548 +        sys.exit(3)
   7.549 +
   7.550 +    if 'PYTHONHOME' in os.environ:
   7.551 +        logger.warn('PYTHONHOME is set.  You *must* activate the virtualenv before using it')
   7.552 +        del os.environ['PYTHONHOME']
   7.553 +
   7.554 +    if options.relocatable:
   7.555 +        make_environment_relocatable(home_dir)
   7.556 +        return
   7.557 +
   7.558 +    create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
   7.559 +                       unzip_setuptools=options.unzip_setuptools,
   7.560 +                       use_distribute=options.use_distribute,
   7.561 +                       prompt=options.prompt)
   7.562 +    if 'after_install' in globals():
   7.563 +        after_install(options, home_dir)
   7.564 +
   7.565 +def call_subprocess(cmd, show_stdout=True,
   7.566 +                    filter_stdout=None, cwd=None,
   7.567 +                    raise_on_returncode=True, extra_env=None,
   7.568 +                    remove_from_env=None):
   7.569 +    cmd_parts = []
   7.570 +    for part in cmd:
   7.571 +        if len(part) > 40:
   7.572 +            part = part[:30]+"..."+part[-5:]
   7.573 +        if ' ' in part or '\n' in part or '"' in part or "'" in part:
   7.574 +            part = '"%s"' % part.replace('"', '\\"')
   7.575 +        cmd_parts.append(part)
   7.576 +    cmd_desc = ' '.join(cmd_parts)
   7.577 +    if show_stdout:
   7.578 +        stdout = None
   7.579 +    else:
   7.580 +        stdout = subprocess.PIPE
   7.581 +    logger.debug("Running command %s" % cmd_desc)
   7.582 +    if extra_env or remove_from_env:
   7.583 +        env = os.environ.copy()
   7.584 +        if extra_env:
   7.585 +            env.update(extra_env)
   7.586 +        if remove_from_env:
   7.587 +            for varname in remove_from_env:
   7.588 +                env.pop(varname, None)
   7.589 +    else:
   7.590 +        env = None
   7.591 +    try:
   7.592 +        proc = subprocess.Popen(
   7.593 +            cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
   7.594 +            cwd=cwd, env=env)
   7.595 +    except Exception, e:
   7.596 +        logger.fatal(
   7.597 +            "Error %s while executing command %s" % (e, cmd_desc))
   7.598 +        raise
   7.599 +    all_output = []
   7.600 +    if stdout is not None:
   7.601 +        stdout = proc.stdout
   7.602 +        while 1:
   7.603 +            line = stdout.readline()
   7.604 +            if not line:
   7.605 +                break
   7.606 +            line = line.rstrip()
   7.607 +            all_output.append(line)
   7.608 +            if filter_stdout:
   7.609 +                level = filter_stdout(line)
   7.610 +                if isinstance(level, tuple):
   7.611 +                    level, line = level
   7.612 +                logger.log(level, line)
   7.613 +                if not logger.stdout_level_matches(level):
   7.614 +                    logger.show_progress()
   7.615 +            else:
   7.616 +                logger.info(line)
   7.617 +    else:
   7.618 +        proc.communicate()
   7.619 +    proc.wait()
   7.620 +    if proc.returncode:
   7.621 +        if raise_on_returncode:
   7.622 +            if all_output:
   7.623 +                logger.notify('Complete output from command %s:' % cmd_desc)
   7.624 +                logger.notify('\n'.join(all_output) + '\n----------------------------------------')
   7.625 +            raise OSError(
   7.626 +                "Command %s failed with error code %s"
   7.627 +                % (cmd_desc, proc.returncode))
   7.628 +        else:
   7.629 +            logger.warn(
   7.630 +                "Command %s had error code %s"
   7.631 +                % (cmd_desc, proc.returncode))
   7.632 +
   7.633 +
   7.634 +def create_environment(home_dir, site_packages=True, clear=False,
   7.635 +                       unzip_setuptools=False, use_distribute=False,
   7.636 +                       prompt=None):
   7.637 +    """
   7.638 +    Creates a new environment in ``home_dir``.
   7.639 +
   7.640 +    If ``site_packages`` is true (the default) then the global
   7.641 +    ``site-packages/`` directory will be on the path.
   7.642 +
   7.643 +    If ``clear`` is true (default False) then the environment will
   7.644 +    first be cleared.
   7.645 +    """
   7.646 +    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
   7.647 +
   7.648 +    py_executable = os.path.abspath(install_python(
   7.649 +        home_dir, lib_dir, inc_dir, bin_dir,
   7.650 +        site_packages=site_packages, clear=clear))
   7.651 +
   7.652 +    install_distutils(home_dir)
   7.653 +
   7.654 +    if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
   7.655 +        install_distribute(py_executable, unzip=unzip_setuptools)
   7.656 +    else:
   7.657 +        install_setuptools(py_executable, unzip=unzip_setuptools)
   7.658 +
   7.659 +    install_pip(py_executable)
   7.660 +
   7.661 +    install_activate(home_dir, bin_dir, prompt)
   7.662 +
   7.663 +def path_locations(home_dir):
   7.664 +    """Return the path locations for the environment (where libraries are,
   7.665 +    where scripts go, etc)"""
   7.666 +    # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
   7.667 +    # prefix arg is broken: http://bugs.python.org/issue3386
   7.668 +    if sys.platform == 'win32':
   7.669 +        # Windows has lots of problems with executables with spaces in
   7.670 +        # the name; this function will remove them (using the ~1
   7.671 +        # format):
   7.672 +        mkdir(home_dir)
   7.673 +        if ' ' in home_dir:
   7.674 +            try:
   7.675 +                import win32api
   7.676 +            except ImportError:
   7.677 +                print 'Error: the path "%s" has a space in it' % home_dir
   7.678 +                print 'To handle these kinds of paths, the win32api module must be installed:'
   7.679 +                print '  http://sourceforge.net/projects/pywin32/'
   7.680 +                sys.exit(3)
   7.681 +            home_dir = win32api.GetShortPathName(home_dir)
   7.682 +        lib_dir = join(home_dir, 'Lib')
   7.683 +        inc_dir = join(home_dir, 'Include')
   7.684 +        bin_dir = join(home_dir, 'Scripts')
   7.685 +    elif is_jython:
   7.686 +        lib_dir = join(home_dir, 'Lib')
   7.687 +        inc_dir = join(home_dir, 'Include')
   7.688 +        bin_dir = join(home_dir, 'bin')
   7.689 +    elif is_pypy:
   7.690 +        lib_dir = home_dir
   7.691 +        inc_dir = join(home_dir, 'include')
   7.692 +        bin_dir = join(home_dir, 'bin')
   7.693 +    else:
   7.694 +        lib_dir = join(home_dir, 'lib', py_version)
   7.695 +        inc_dir = join(home_dir, 'include', py_version)
   7.696 +        bin_dir = join(home_dir, 'bin')
   7.697 +    return home_dir, lib_dir, inc_dir, bin_dir
   7.698 +
   7.699 +
   7.700 +def change_prefix(filename, dst_prefix):
   7.701 +    prefixes = [sys.prefix]
   7.702 +    if hasattr(sys, 'real_prefix'):
   7.703 +        prefixes.append(sys.real_prefix)
   7.704 +    prefixes = map(os.path.abspath, prefixes)
   7.705 +    filename = os.path.abspath(filename)
   7.706 +    for src_prefix in prefixes:
   7.707 +        if filename.startswith(src_prefix):
   7.708 +            _, relpath = filename.split(src_prefix, 1)
   7.709 +            assert relpath[0] == os.sep
   7.710 +            relpath = relpath[1:]
   7.711 +            return join(dst_prefix, relpath)
   7.712 +    assert False, "Filename %s does not start with any of these prefixes: %s" % \
   7.713 +        (filename, prefixes)
   7.714 +
   7.715 +def copy_required_modules(dst_prefix):
   7.716 +    import imp
   7.717 +    for modname in REQUIRED_MODULES:
   7.718 +        if modname in sys.builtin_module_names:
   7.719 +            logger.info("Ignoring built-in bootstrap module: %s" % modname)
   7.720 +            continue
   7.721 +        try:
   7.722 +            f, filename, _ = imp.find_module(modname)
   7.723 +        except ImportError:
   7.724 +            logger.info("Cannot import bootstrap module: %s" % modname)
   7.725 +        else:
   7.726 +            if f is not None:
   7.727 +                f.close()
   7.728 +            dst_filename = change_prefix(filename, dst_prefix)
   7.729 +            copyfile(filename, dst_filename)
   7.730 +            if filename.endswith('.pyc'):
   7.731 +                pyfile = filename[:-1]
   7.732 +                if os.path.exists(pyfile):
   7.733 +                    copyfile(pyfile, dst_filename[:-1])
   7.734 +
   7.735 +
   7.736 +def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
   7.737 +    """Install just the base environment, no distutils patches etc"""
   7.738 +    if sys.executable.startswith(bin_dir):
   7.739 +        print 'Please use the *system* python to run this script'
   7.740 +        return
   7.741 +
   7.742 +    if clear:
   7.743 +        rmtree(lib_dir)
   7.744 +        ## FIXME: why not delete it?
   7.745 +        ## Maybe it should delete everything with #!/path/to/venv/python in it
   7.746 +        logger.notify('Not deleting %s', bin_dir)
   7.747 +
   7.748 +    if hasattr(sys, 'real_prefix'):
   7.749 +        logger.notify('Using real prefix %r' % sys.real_prefix)
   7.750 +        prefix = sys.real_prefix
   7.751 +    else:
   7.752 +        prefix = sys.prefix
   7.753 +    mkdir(lib_dir)
   7.754 +    fix_lib64(lib_dir)
   7.755 +    stdlib_dirs = [os.path.dirname(os.__file__)]
   7.756 +    if sys.platform == 'win32':
   7.757 +        stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
   7.758 +    elif sys.platform == 'darwin':
   7.759 +        stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
   7.760 +    if hasattr(os, 'symlink'):
   7.761 +        logger.info('Symlinking Python bootstrap modules')
   7.762 +    else:
   7.763 +        logger.info('Copying Python bootstrap modules')
   7.764 +    logger.indent += 2
   7.765 +    try:
   7.766 +        # copy required files...
   7.767 +        for stdlib_dir in stdlib_dirs:
   7.768 +            if not os.path.isdir(stdlib_dir):
   7.769 +                continue
   7.770 +            for fn in os.listdir(stdlib_dir):
   7.771 +                if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_FILES:
   7.772 +                    copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
   7.773 +        # ...and modules
   7.774 +        copy_required_modules(home_dir)
   7.775 +    finally:
   7.776 +        logger.indent -= 2
   7.777 +    mkdir(join(lib_dir, 'site-packages'))
   7.778 +    import site
   7.779 +    site_filename = site.__file__
   7.780 +    if site_filename.endswith('.pyc'):
   7.781 +        site_filename = site_filename[:-1]
   7.782 +    elif site_filename.endswith('$py.class'):
   7.783 +        site_filename = site_filename.replace('$py.class', '.py')
   7.784 +    site_filename_dst = change_prefix(site_filename, home_dir)
   7.785 +    site_dir = os.path.dirname(site_filename_dst)
   7.786 +    writefile(site_filename_dst, SITE_PY)
   7.787 +    writefile(join(site_dir, 'orig-prefix.txt'), prefix)
   7.788 +    site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
   7.789 +    if not site_packages:
   7.790 +        writefile(site_packages_filename, '')
   7.791 +    else:
   7.792 +        if os.path.exists(site_packages_filename):
   7.793 +            logger.info('Deleting %s' % site_packages_filename)
   7.794 +            os.unlink(site_packages_filename)
   7.795 +
   7.796 +    if is_pypy:
   7.797 +        stdinc_dir = join(prefix, 'include')
   7.798 +    else:
   7.799 +        stdinc_dir = join(prefix, 'include', py_version)
   7.800 +    if os.path.exists(stdinc_dir):
   7.801 +        copyfile(stdinc_dir, inc_dir)
   7.802 +    else:
   7.803 +        logger.debug('No include dir %s' % stdinc_dir)
   7.804 +
   7.805 +    if sys.exec_prefix != prefix:
   7.806 +        if sys.platform == 'win32':
   7.807 +            exec_dir = join(sys.exec_prefix, 'lib')
   7.808 +        elif is_jython:
   7.809 +            exec_dir = join(sys.exec_prefix, 'Lib')
   7.810 +        else:
   7.811 +            exec_dir = join(sys.exec_prefix, 'lib', py_version)
   7.812 +        for fn in os.listdir(exec_dir):
   7.813 +            copyfile(join(exec_dir, fn), join(lib_dir, fn))
   7.814 +
   7.815 +    if is_jython:
   7.816 +        # Jython has either jython-dev.jar and javalib/ dir, or just
   7.817 +        # jython.jar
   7.818 +        for name in 'jython-dev.jar', 'javalib', 'jython.jar':
   7.819 +            src = join(prefix, name)
   7.820 +            if os.path.exists(src):
   7.821 +                copyfile(src, join(home_dir, name))
   7.822 +        # XXX: registry should always exist after Jython 2.5rc1
   7.823 +        src = join(prefix, 'registry')
   7.824 +        if os.path.exists(src):
   7.825 +            copyfile(src, join(home_dir, 'registry'), symlink=False)
   7.826 +        copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
   7.827 +                 symlink=False)
   7.828 +
   7.829 +    mkdir(bin_dir)
   7.830 +    py_executable = join(bin_dir, os.path.basename(sys.executable))
   7.831 +    if 'Python.framework' in prefix:
   7.832 +        if re.search(r'/Python(?:-32|-64)*$', py_executable):
   7.833 +            # The name of the python executable is not quite what
   7.834 +            # we want, rename it.
   7.835 +            py_executable = os.path.join(
   7.836 +                    os.path.dirname(py_executable), 'python')
   7.837 +
   7.838 +    logger.notify('New %s executable in %s', expected_exe, py_executable)
   7.839 +    if sys.executable != py_executable:
   7.840 +        ## FIXME: could I just hard link?
   7.841 +        executable = sys.executable
   7.842 +        if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
   7.843 +            # Cygwin misreports sys.executable sometimes
   7.844 +            executable += '.exe'
   7.845 +            py_executable += '.exe'
   7.846 +            logger.info('Executable actually exists in %s' % executable)
   7.847 +        shutil.copyfile(executable, py_executable)
   7.848 +        make_exe(py_executable)
   7.849 +        if sys.platform == 'win32' or sys.platform == 'cygwin':
   7.850 +            pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
   7.851 +            if os.path.exists(pythonw):
   7.852 +                logger.info('Also created pythonw.exe')
   7.853 +                shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
   7.854 +        if is_pypy:
   7.855 +            # make a symlink python --> pypy-c
   7.856 +            python_executable = os.path.join(os.path.dirname(py_executable), 'python')
   7.857 +            logger.info('Also created executable %s' % python_executable)
   7.858 +            copyfile(py_executable, python_executable)
   7.859 +
   7.860 +    if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
   7.861 +        secondary_exe = os.path.join(os.path.dirname(py_executable),
   7.862 +                                     expected_exe)
   7.863 +        py_executable_ext = os.path.splitext(py_executable)[1]
   7.864 +        if py_executable_ext == '.exe':
   7.865 +            # python2.4 gives an extension of '.4' :P
   7.866 +            secondary_exe += py_executable_ext
   7.867 +        if os.path.exists(secondary_exe):
   7.868 +            logger.warn('Not overwriting existing %s script %s (you must use %s)'
   7.869 +                        % (expected_exe, secondary_exe, py_executable))
   7.870 +        else:
   7.871 +            logger.notify('Also creating executable in %s' % secondary_exe)
   7.872 +            shutil.copyfile(sys.executable, secondary_exe)
   7.873 +            make_exe(secondary_exe)
   7.874 +
   7.875 +    if 'Python.framework' in prefix:
   7.876 +        logger.debug('MacOSX Python framework detected')
   7.877 +
   7.878 +        # Make sure we use the the embedded interpreter inside
   7.879 +        # the framework, even if sys.executable points to
   7.880 +        # the stub executable in ${sys.prefix}/bin
   7.881 +        # See http://groups.google.com/group/python-virtualenv/
   7.882 +        #                              browse_thread/thread/17cab2f85da75951
   7.883 +        original_python = os.path.join(
   7.884 +            prefix, 'Resources/Python.app/Contents/MacOS/Python')
   7.885 +        shutil.copy(original_python, py_executable)
   7.886 +
   7.887 +        # Copy the framework's dylib into the virtual
   7.888 +        # environment
   7.889 +        virtual_lib = os.path.join(home_dir, '.Python')
   7.890 +
   7.891 +        if os.path.exists(virtual_lib):
   7.892 +            os.unlink(virtual_lib)
   7.893 +        copyfile(
   7.894 +            os.path.join(prefix, 'Python'),
   7.895 +            virtual_lib)
   7.896 +
   7.897 +        # And then change the install_name of the copied python executable
   7.898 +        try:
   7.899 +            call_subprocess(
   7.900 +                ["install_name_tool", "-change",
   7.901 +                 os.path.join(prefix, 'Python'),
   7.902 +                 '@executable_path/../.Python',
   7.903 +                 py_executable])
   7.904 +        except:
   7.905 +            logger.fatal(
   7.906 +                "Could not call install_name_tool -- you must have Apple's development tools installed")
   7.907 +            raise
   7.908 +
   7.909 +        # Some tools depend on pythonX.Y being present
   7.910 +        py_executable_version = '%s.%s' % (
   7.911 +            sys.version_info[0], sys.version_info[1])
   7.912 +        if not py_executable.endswith(py_executable_version):
   7.913 +            # symlinking pythonX.Y > python
   7.914 +            pth = py_executable + '%s.%s' % (
   7.915 +                    sys.version_info[0], sys.version_info[1])
   7.916 +            if os.path.exists(pth):
   7.917 +                os.unlink(pth)
   7.918 +            os.symlink('python', pth)
   7.919 +        else:
   7.920 +            # reverse symlinking python -> pythonX.Y (with --python)
   7.921 +            pth = join(bin_dir, 'python')
   7.922 +            if os.path.exists(pth):
   7.923 +                os.unlink(pth)
   7.924 +            os.symlink(os.path.basename(py_executable), pth)
   7.925 +
   7.926 +    if sys.platform == 'win32' and ' ' in py_executable:
   7.927 +        # There's a bug with subprocess on Windows when using a first
   7.928 +        # argument that has a space in it.  Instead we have to quote
   7.929 +        # the value:
   7.930 +        py_executable = '"%s"' % py_executable
   7.931 +    cmd = [py_executable, '-c', 'import sys; print sys.prefix']
   7.932 +    logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
   7.933 +    proc = subprocess.Popen(cmd,
   7.934 +                            stdout=subprocess.PIPE)
   7.935 +    proc_stdout, proc_stderr = proc.communicate()
   7.936 +    proc_stdout = os.path.normcase(os.path.abspath(proc_stdout.strip()))
   7.937 +    if proc_stdout != os.path.normcase(os.path.abspath(home_dir)):
   7.938 +        logger.fatal(
   7.939 +            'ERROR: The executable %s is not functioning' % py_executable)
   7.940 +        logger.fatal(
   7.941 +            'ERROR: It thinks sys.prefix is %r (should be %r)'
   7.942 +            % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
   7.943 +        logger.fatal(
   7.944 +            'ERROR: virtualenv is not compatible with this system or executable')
   7.945 +        if sys.platform == 'win32':
   7.946 +            logger.fatal(
   7.947 +                'Note: some Windows users have reported this error when they installed Python for "Only this user".  The problem may be resolvable if you install Python "For all users".  (See https://bugs.launchpad.net/virtualenv/+bug/352844)')
   7.948 +        sys.exit(100)
   7.949 +    else:
   7.950 +        logger.info('Got sys.prefix result: %r' % proc_stdout)
   7.951 +
   7.952 +    pydistutils = os.path.expanduser('~/.pydistutils.cfg')
   7.953 +    if os.path.exists(pydistutils):
   7.954 +        logger.notify('Please make sure you remove any previous custom paths from '
   7.955 +                      'your %s file.' % pydistutils)
   7.956 +    ## FIXME: really this should be calculated earlier
   7.957 +    return py_executable
   7.958 +
   7.959 +def install_activate(home_dir, bin_dir, prompt=None):
   7.960 +    if sys.platform == 'win32' or is_jython and os._name == 'nt':
   7.961 +        files = {'activate.bat': ACTIVATE_BAT,
   7.962 +                 'deactivate.bat': DEACTIVATE_BAT}
   7.963 +        if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
   7.964 +            files['activate'] = ACTIVATE_SH
   7.965 +    else:
   7.966 +        files = {'activate': ACTIVATE_SH}
   7.967 +
   7.968 +        # suppling activate.fish in addition to, not instead of, the
   7.969 +        # bash script support.
   7.970 +        files['activate.fish'] = ACTIVATE_FISH
   7.971 +
   7.972 +        # same for csh/tcsh support...
   7.973 +        files['activate.csh'] = ACTIVATE_CSH
   7.974 +
   7.975 +
   7.976 +
   7.977 +    files['activate_this.py'] = ACTIVATE_THIS
   7.978 +    vname = os.path.basename(os.path.abspath(home_dir))
   7.979 +    for name, content in files.items():
   7.980 +        content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
   7.981 +        content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
   7.982 +        content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir))
   7.983 +        content = content.replace('__VIRTUAL_NAME__', vname)
   7.984 +        content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
   7.985 +        writefile(os.path.join(bin_dir, name), content)
   7.986 +
   7.987 +def install_distutils(home_dir):
   7.988 +    distutils_path = change_prefix(distutils.__path__[0], home_dir)
   7.989 +    mkdir(distutils_path)
   7.990 +    ## FIXME: maybe this prefix setting should only be put in place if
   7.991 +    ## there's a local distutils.cfg with a prefix setting?
   7.992 +    home_dir = os.path.abspath(home_dir)
   7.993 +    ## FIXME: this is breaking things, removing for now:
   7.994 +    #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
   7.995 +    writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
   7.996 +    writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
   7.997 +
   7.998 +def fix_lib64(lib_dir):
   7.999 +    """
  7.1000 +    Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
  7.1001 +    instead of lib/pythonX.Y.  If this is such a platform we'll just create a
  7.1002 +    symlink so lib64 points to lib
  7.1003 +    """
  7.1004 +    if [p for p in distutils.sysconfig.get_config_vars().values()
  7.1005 +        if isinstance(p, basestring) and 'lib64' in p]:
  7.1006 +        logger.debug('This system uses lib64; symlinking lib64 to lib')
  7.1007 +        assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
  7.1008 +            "Unexpected python lib dir: %r" % lib_dir)
  7.1009 +        lib_parent = os.path.dirname(lib_dir)
  7.1010 +        assert os.path.basename(lib_parent) == 'lib', (
  7.1011 +            "Unexpected parent dir: %r" % lib_parent)
  7.1012 +        copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
  7.1013 +
  7.1014 +def resolve_interpreter(exe):
  7.1015 +    """
  7.1016 +    If the executable given isn't an absolute path, search $PATH for the interpreter
  7.1017 +    """
  7.1018 +    if os.path.abspath(exe) != exe:
  7.1019 +        paths = os.environ.get('PATH', '').split(os.pathsep)
  7.1020 +        for path in paths:
  7.1021 +            if os.path.exists(os.path.join(path, exe)):
  7.1022 +                exe = os.path.join(path, exe)
  7.1023 +                break
  7.1024 +    if not os.path.exists(exe):
  7.1025 +        logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
  7.1026 +        sys.exit(3)
  7.1027 +    return exe
  7.1028 +
  7.1029 +############################################################
  7.1030 +## Relocating the environment:
  7.1031 +
  7.1032 +def make_environment_relocatable(home_dir):
  7.1033 +    """
  7.1034 +    Makes the already-existing environment use relative paths, and takes out
  7.1035 +    the #!-based environment selection in scripts.
  7.1036 +    """
  7.1037 +    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
  7.1038 +    activate_this = os.path.join(bin_dir, 'activate_this.py')
  7.1039 +    if not os.path.exists(activate_this):
  7.1040 +        logger.fatal(
  7.1041 +            'The environment doesn\'t have a file %s -- please re-run virtualenv '
  7.1042 +            'on this environment to update it' % activate_this)
  7.1043 +    fixup_scripts(home_dir)
  7.1044 +    fixup_pth_and_egg_link(home_dir)
  7.1045 +    ## FIXME: need to fix up distutils.cfg
  7.1046 +
  7.1047 +OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
  7.1048 +                  'activate', 'activate.bat', 'activate_this.py']
  7.1049 +
  7.1050 +def fixup_scripts(home_dir):
  7.1051 +    # This is what we expect at the top of scripts:
  7.1052 +    shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
  7.1053 +    # This is what we'll put:
  7.1054 +    new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
  7.1055 +    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"
  7.1056 +    if sys.platform == 'win32':
  7.1057 +        bin_suffix = 'Scripts'
  7.1058 +    else:
  7.1059 +        bin_suffix = 'bin'
  7.1060 +    bin_dir = os.path.join(home_dir, bin_suffix)
  7.1061 +    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
  7.1062 +    for filename in os.listdir(bin_dir):
  7.1063 +        filename = os.path.join(bin_dir, filename)
  7.1064 +        if not os.path.isfile(filename):
  7.1065 +            # ignore subdirs, e.g. .svn ones.
  7.1066 +            continue
  7.1067 +        f = open(filename, 'rb')
  7.1068 +        lines = f.readlines()
  7.1069 +        f.close()
  7.1070 +        if not lines:
  7.1071 +            logger.warn('Script %s is an empty file' % filename)
  7.1072 +            continue
  7.1073 +        if not lines[0].strip().startswith(shebang):
  7.1074 +            if os.path.basename(filename) in OK_ABS_SCRIPTS:
  7.1075 +                logger.debug('Cannot make script %s relative' % filename)
  7.1076 +            elif lines[0].strip() == new_shebang:
  7.1077 +                logger.info('Script %s has already been made relative' % filename)
  7.1078 +            else:
  7.1079 +                logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
  7.1080 +                            % (filename, shebang))
  7.1081 +            continue
  7.1082 +        logger.notify('Making script %s relative' % filename)
  7.1083 +        lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
  7.1084 +        f = open(filename, 'wb')
  7.1085 +        f.writelines(lines)
  7.1086 +        f.close()
  7.1087 +
  7.1088 +def fixup_pth_and_egg_link(home_dir, sys_path=None):
  7.1089 +    """Makes .pth and .egg-link files use relative paths"""
  7.1090 +    home_dir = os.path.normcase(os.path.abspath(home_dir))
  7.1091 +    if sys_path is None:
  7.1092 +        sys_path = sys.path
  7.1093 +    for path in sys_path:
  7.1094 +        if not path:
  7.1095 +            path = '.'
  7.1096 +        if not os.path.isdir(path):
  7.1097 +            continue
  7.1098 +        path = os.path.normcase(os.path.abspath(path))
  7.1099 +        if not path.startswith(home_dir):
  7.1100 +            logger.debug('Skipping system (non-environment) directory %s' % path)
  7.1101 +            continue
  7.1102 +        for filename in os.listdir(path):
  7.1103 +            filename = os.path.join(path, filename)
  7.1104 +            if filename.endswith('.pth'):
  7.1105 +                if not os.access(filename, os.W_OK):
  7.1106 +                    logger.warn('Cannot write .pth file %s, skipping' % filename)
  7.1107 +                else:
  7.1108 +                    fixup_pth_file(filename)
  7.1109 +            if filename.endswith('.egg-link'):
  7.1110 +                if not os.access(filename, os.W_OK):
  7.1111 +                    logger.warn('Cannot write .egg-link file %s, skipping' % filename)
  7.1112 +                else:
  7.1113 +                    fixup_egg_link(filename)
  7.1114 +
  7.1115 +def fixup_pth_file(filename):
  7.1116 +    lines = []
  7.1117 +    prev_lines = []
  7.1118 +    f = open(filename)
  7.1119 +    prev_lines = f.readlines()
  7.1120 +    f.close()
  7.1121 +    for line in prev_lines:
  7.1122 +        line = line.strip()
  7.1123 +        if (not line or line.startswith('#') or line.startswith('import ')
  7.1124 +            or os.path.abspath(line) != line):
  7.1125 +            lines.append(line)
  7.1126 +        else:
  7.1127 +            new_value = make_relative_path(filename, line)
  7.1128 +            if line != new_value:
  7.1129 +                logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
  7.1130 +            lines.append(new_value)
  7.1131 +    if lines == prev_lines:
  7.1132 +        logger.info('No changes to .pth file %s' % filename)
  7.1133 +        return
  7.1134 +    logger.notify('Making paths in .pth file %s relative' % filename)
  7.1135 +    f = open(filename, 'w')
  7.1136 +    f.write('\n'.join(lines) + '\n')
  7.1137 +    f.close()
  7.1138 +
  7.1139 +def fixup_egg_link(filename):
  7.1140 +    f = open(filename)
  7.1141 +    link = f.read().strip()
  7.1142 +    f.close()
  7.1143 +    if os.path.abspath(link) != link:
  7.1144 +        logger.debug('Link in %s already relative' % filename)
  7.1145 +        return
  7.1146 +    new_link = make_relative_path(filename, link)
  7.1147 +    logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
  7.1148 +    f = open(filename, 'w')
  7.1149 +    f.write(new_link)
  7.1150 +    f.close()
  7.1151 +
  7.1152 +def make_relative_path(source, dest, dest_is_directory=True):
  7.1153 +    """
  7.1154 +    Make a filename relative, where the filename is dest, and it is
  7.1155 +    being referred to from the filename source.
  7.1156 +
  7.1157 +        >>> make_relative_path('/usr/share/something/a-file.pth',
  7.1158 +        ...                    '/usr/share/another-place/src/Directory')
  7.1159 +        '../another-place/src/Directory'
  7.1160 +        >>> make_relative_path('/usr/share/something/a-file.pth',
  7.1161 +        ...                    '/home/user/src/Directory')
  7.1162 +        '../../../home/user/src/Directory'
  7.1163 +        >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
  7.1164 +        './'
  7.1165 +    """
  7.1166 +    source = os.path.dirname(source)
  7.1167 +    if not dest_is_directory:
  7.1168 +        dest_filename = os.path.basename(dest)
  7.1169 +        dest = os.path.dirname(dest)
  7.1170 +    dest = os.path.normpath(os.path.abspath(dest))
  7.1171 +    source = os.path.normpath(os.path.abspath(source))
  7.1172 +    dest_parts = dest.strip(os.path.sep).split(os.path.sep)
  7.1173 +    source_parts = source.strip(os.path.sep).split(os.path.sep)
  7.1174 +    while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
  7.1175 +        dest_parts.pop(0)
  7.1176 +        source_parts.pop(0)
  7.1177 +    full_parts = ['..']*len(source_parts) + dest_parts
  7.1178 +    if not dest_is_directory:
  7.1179 +        full_parts.append(dest_filename)
  7.1180 +    if not full_parts:
  7.1181 +        # Special case for the current directory (otherwise it'd be '')
  7.1182 +        return './'
  7.1183 +    return os.path.sep.join(full_parts)
  7.1184 +
  7.1185 +
  7.1186 +
  7.1187 +############################################################
  7.1188 +## Bootstrap script creation:
  7.1189 +
  7.1190 +def create_bootstrap_script(extra_text, python_version=''):
  7.1191 +    """
  7.1192 +    Creates a bootstrap script, which is like this script but with
  7.1193 +    extend_parser, adjust_options, and after_install hooks.
  7.1194 +
  7.1195 +    This returns a string that (written to disk of course) can be used
  7.1196 +    as a bootstrap script with your own customizations.  The script
  7.1197 +    will be the standard virtualenv.py script, with your extra text
  7.1198 +    added (your extra text should be Python code).
  7.1199 +
  7.1200 +    If you include these functions, they will be called:
  7.1201 +
  7.1202 +    ``extend_parser(optparse_parser)``:
  7.1203 +        You can add or remove options from the parser here.
  7.1204 +
  7.1205 +    ``adjust_options(options, args)``:
  7.1206 +        You can change options here, or change the args (if you accept
  7.1207 +        different kinds of arguments, be sure you modify ``args`` so it is
  7.1208 +        only ``[DEST_DIR]``).
  7.1209 +
  7.1210 +    ``after_install(options, home_dir)``:
  7.1211 +
  7.1212 +        After everything is installed, this function is called.  This
  7.1213 +        is probably the function you are most likely to use.  An
  7.1214 +        example would be::
  7.1215 +
  7.1216 +            def after_install(options, home_dir):
  7.1217 +                subprocess.call([join(home_dir, 'bin', 'easy_install'),
  7.1218 +                                 'MyPackage'])
  7.1219 +                subprocess.call([join(home_dir, 'bin', 'my-package-script'),
  7.1220 +                                 'setup', home_dir])
  7.1221 +
  7.1222 +        This example immediately installs a package, and runs a setup
  7.1223 +        script from that package.
  7.1224 +
  7.1225 +    If you provide something like ``python_version='2.4'`` then the
  7.1226 +    script will start with ``#!/usr/bin/env python2.4`` instead of
  7.1227 +    ``#!/usr/bin/env python``.  You can use this when the script must
  7.1228 +    be run with a particular Python version.
  7.1229 +    """
  7.1230 +    filename = __file__
  7.1231 +    if filename.endswith('.pyc'):
  7.1232 +        filename = filename[:-1]
  7.1233 +    f = open(filename, 'rb')
  7.1234 +    content = f.read()
  7.1235 +    f.close()
  7.1236 +    py_exe = 'python%s' % python_version
  7.1237 +    content = (('#!/usr/bin/env %s\n' % py_exe)
  7.1238 +               + '## WARNING: This file is generated\n'
  7.1239 +               + content)
  7.1240 +    return content.replace('##EXT' 'END##', extra_text)
  7.1241 +
  7.1242 +##EXTEND##
  7.1243 +
  7.1244 +##file site.py
  7.1245 +SITE_PY = """
  7.1246 +eJzVPP1z2zaWv/OvQOXJUEplOh/dzo5T98ZJnNZ7buJt0mluXY+WkiCJNUWyBGlZe3P3t9/7AECA
  7.1247 +pGS77f5wmkwskcDDw8P7xgMGg8FpUchsLtb5vE6lUDIuZytRxNVKiUVeimqVlPPDIi6rLTyd3cRL
  7.1248 +qUSVC7VVEbaKguDpH/wET8WnVaIMCvAtrqt8HVfJLE7TrUjWRV5Wci7mdZlkS5FkSZXEafIvaJFn
  7.1249 +kXj6xzEIzjMBM08TWYpbWSqAq0S+EJfbapVnYlgXOOfn0V/il6OxULMyKSpoUGqcgSKruAoyKeeA
  7.1250 +JrSsFZAyqeShKuQsWSQz23CT1+lcFGk8k+Kf/+SpUdMwDFS+lpuVLKXIABmAKQFWgXjA16QUs3wu
  7.1251 +IyFey1mMA/DzhlgBQxvjmikkY5aLNM+WMKdMzqRScbkVw2ldESBCWcxzwCkBDKokTYNNXt6oESwp
  7.1252 +rccGHomY2cOfDLMHzBPH73IO4PghC37KkrsxwwbuQXDVitmmlIvkTsQIFn7KOzmb6GfDZCHmyWIB
  7.1253 +NMiqETYJGAEl0mR6VNByfKNX6NsjwspyZQxjSESZG/NL6hEF55WIUwVsWxdII0WYv5XTJM6AGtkt
  7.1254 +DAcQgaRB3zjzRFV2HJqdyAFAietYgZSslRiu4yQDZv0hnhHaPyfZPN+oEVEAVkuJX2tVufMf9hAA
  7.1255 +WjsEGAe4WGY16yxNbmS6HQECnwD7Uqo6rVAg5kkpZ1VeJlIRAEBtK+QdID0WcSk1CZkzjdyOif5E
  7.1256 +kyTDhUUBQ4HHl0iSRbKsS5IwsUiAc4Er3n34Ubw9e31++l7zmAHGMrtcA84AhRbawQkGEEe1Ko/S
  7.1257 +HAQ6Ci7wj4jncxSyJY4PeDUNju5d6WAIcy+idh9nwYHsenH1MDDHCpQJjRVQv/+GLmO1Avr8zz3r
  7.1258 +HQSnu6hCE+dvm1UOMpnFaylWMfMXckbwjYbzbVRUq1fADQrhVEAqhYuDCCYID0ji0myYZ1IUwGJp
  7.1259 +kslRABSaUlt/FYEV3ufZIa11ixMAQhlk8NJ5NqIRMwkT7cJ6hfrCNN7SzHSTwK7zOi9JcQD/ZzPS
  7.1260 +RWmc3RCOihiKv03lMskyRAh5IQgPQhpY3STAifNIXFAr0gumkQhZe3FLFIkaeAmZDnhS3sXrIpVj
  7.1261 +Fl/UrfvVCA0mK2HWOmWOg5YVqVdatWaqvbz3Ivrc4jpCs1qVEoDXU0/oFnk+FlPQ2YRNEa9ZvKpN
  7.1262 +TpwT9MgTdUKeoJbQF78DRU+VqtfSvkReAc1CDBUs8jTNN0Cy4yAQ4gAbGaPsMye8hXfwP8DF/1NZ
  7.1263 +zVZB4IxkAWtQiPwuUAgETILMNFdrJDxu06zcVjJJxpoiL+eypKEeRuwjRvyBjXGuwfu80kaNp4ur
  7.1264 +nK+TClXSVJvMhC1eFlasH1/xvGEaYLkV0cw0bei0xumlxSqeSuOSTOUCJUEv0iu77DBm0DMm2eJK
  7.1265 +rNnKwDsgi0zYgvQrFlQ6i0qSEwAwWPjiLCnqlBopZDARw0DrguCvYzTpuXaWgL3ZLAeokNh8z8D+
  7.1266 +AG7/AjHarBKgzwwggIZBLQXLN02qEh2ERh8FvtE3/Xl84NTzhbZNPOQiTlJt5eMsOKeHZ2VJ4juT
  7.1267 +BfYaa2IomGFWoWu3zICOKOaDwSAIjDu0VeZrbr9NJtM6QXs3mQRVuT0G7hAo5AFDF+9hojQcv1mU
  7.1268 ++RpfW/Q+gj4AvYw9ggNxSYpCso/rMdMrpICrlQvTFM2vw5ECVUlw+ePZu/PPZx/FibhqtNK4rZKu
  7.1269 +YcyzLAbOJKUOfNEatlFH0BJ1V4LqS7wDC03rCiaJepMEyriqgf0A9U9lTa9hGjPvZXD2/vT1xdnk
  7.1270 +p49nP04+nn86AwTBVMjggKaMFq4Gn09FwN/AWHMVaRMZdHrQg9enH+2DYJKoSbEttvAAbB1wYTmE
  7.1271 ++Y5FiA8n2oxOkmyRhyNq/Cv70SesGbTTdHX81bU4ORHhr/FtHAbguDRNeRF/IB7+tC0kdK3gzzBX
  7.1272 +oyCYywXw+41EqRg+JWd0xB2AiNAy18bx1zzJzHt67Q1BQjukHoDDZDJLY6Ww8WQSAmmpQ88HOkTs
  7.1273 +0SKrD6FjsXW7jjQq+CklLEWGXcb4Xw+K8ZT6IRqMotvFNAIZWc9iJbkVTR/6TSaoKCaToR4QJIh4
  7.1274 +HLwclv1QmCaoKMoEnEniFVQcU5Wn+BPho+iRyGA8g6oJF0nHK9FtnNZSDZ1JARGHwxYZUbslijgI
  7.1275 +/IIhmL9m6UajNjUNz0AzIF+ag+oqW5TDzwE4GaAjTOSE0RUHPEwzxPRv7N4TDuDnhahjlWpBYZUk
  7.1276 +Ls8uxctnLw7Rh4BAb26p4zVHs5hktbQPF7BaS1k5CHOvcEzCMHLpskDlhk+P98NcR3Zluqyw0Etc
  7.1277 +ynV+K+eALTKws8riR3oD4TDMYxbDKoIyJSPMSs84azEGfzx7kBY02EC9NUEx62+W/oAjcJkpUB0c
  7.1278 +zRKpdajN9qco89sELfx0q1+CgQL1hmbKeBOBs3Aek6EdAg0BrmeGlNrIEBRYWbOXSHgjSFTx80YV
  7.1279 +RgTuAnXrNX29yfJNNuHw8wTV5HBkWRcFSzMvNmiW4EC8A8MBSOYQTTVEYyjgZwuUrUNAHqYP0wXK
  7.1280 +kkMPgMC6KoqRHFgmvqIpcqiGwyKM0StBwltKNNK3ZgiKbwwxHEj0NrIPjJZASDA5q+CsatBMhrJm
  7.1281 +msHADkl8rruIOO7zAbSoGIGhG2po3MjQ7+oYlLO4cJWS0w9t6OfPn5lt1IqSGojYFCeNdntB5i0q
  7.1282 +tmAKE9AJxg3iFAmxwQY8SgBTK82a4vCjyAt2gWA9L7Vsg+WGkKqqiuOjo81mE+mQPi+XR2px9Je/
  7.1283 +fv31X5+xTpzPiX9gOo606PxWdETv0I2MvjEW6Fuzci1+TDKfGwnWUJIrRP4f4vddncxzcXw4svoT
  7.1284 +ubgxrPi/cT5AgUzMoExloO2gweiJOnwSvVQD8UQM3bbDEXsS2qRaK+ZbXehR5WC7wdOY5XVWhY4i
  7.1285 +VeJLsG4QFs/ltF6GdnDPRpofMFWU06HlgcPn14iBzxmGr4wpnqCWILZAi++Q/kdmm5j8Ga0hkLxo
  7.1286 +ojoh67Zfixnizh8u79Y7dITGzDBRyB0oEX6TBwugbdyVHPxoZxTtnuOMmo9nCIylDwzzaldwiIJD
  7.1287 +uOBajF2pc7gafVSQpg2rZlAwrmoEBQ1u3ZSprcGRjQwRJHo3JsLmhdUtgE6tdJ0Jys0qQAt3nI61
  7.1288 +a7OC4wkhD5yI5/REglN73Hn3jJe2TlPKorR41KMKA/YWGu10Dnw5NADGYlD+NOCWelnOP7QWhdeg
  7.1289 +B1jOiRdksEWHmfCN6wMODgY97NSx+rt6M437QOAiUfuHASeMT3iAUoEwFUOfcXdxuKUtJ5taCO82
  7.1290 +OMRTZpVIotUO2Wrrjl6Z2muXFkmGqtdZo2iW5uAUW6VIfNS8930FClzwcZ8t0wKoydCQw2l0Qs6e
  7.1291 +J3+hbocpq2WNwb2b+0CM1oki44ZkWsF/4FVQToESQEBLgmbBPFTI/In9CSJn56u/7GAPS2hkCLfp
  7.1292 +Li+kYzA0HPP+QCAZdQYEhCADEnZlkTxH1gYpcJizQJ5sw2u5U7gJRqRAzBwDQloGcKeXXnyDTyLc
  7.1293 +dSABRch3lZKF+FIMYPnakvow1f2ncqnJGgydBuQp6HTDiZuKcNIQJ620hM/QfkKC9ieKHDh4Ch6P
  7.1294 +m1x32dwwrc2SgK/u622LFChkSpwMRi6q14YwbgL3ixOnRUMsM4hhKG8gbxvFjDQK7HJr0LDgBoy3
  7.1295 +5u2x9GM3YYF9h2GuXsj1HYR/YZmoWa5CjG87qQv3o7miSxuL7UUyHcAfbwEGo2sPkkx1+gKTLL9j
  7.1296 +kNCDHvZB9yaLWZF5XG6SLCQFpul34i9NBw9LSs/GHX2kaOoIJopZxqN3JQgIbTcegTihJoCgXIZK
  7.1297 +e/1dsHunOLBwufvA85qvjl9ed4k73pXgsZ/+pTq7q8pY4WqlvGgsFLhaXfuNShcmF2dbvWGoN5Qx
  7.1298 +SihzBUGk+PDxs0BCcC51E28fN/WG4RGbe+fkfQzqoNfuJVdrdsQugAhqRWSUo/DxHPlwZB87uT0T
  7.1299 +ewSQRzHMnkUxkDSf/B44+xYKxjicbzNMo7VVBn7g9ddfTXoSoy6SX381uGeUFjH6xH7Y8gTtyLSR
  7.1300 +L3qnbbqUMk7J13A6UVIxa3jHtilGrNAp/NNMdt3jdOLHvDcmo4Hfad6JG83ngOgBUXY+/RViVaXT
  7.1301 +W7dxklJOHtA4PEQ9Z8Jszhz04+NB2o8ypqTAY3k27o2E1NUzWJiQ4/pRdzraLzo1qd+eeNR8ilh1
  7.1302 +UTnQW+jNDpC3Le7u/u2W/V5L/W/SWY8E5M1m0EPAB87B7E7+/58JKyuGppXVqKX1ldyv5w2wB6jD
  7.1303 +HW7OHjekOzRvZi2MM8Fyp8RTFNCnYkNb0pTKw40JgDJnP6MHDi6j3th8U5clb0+SnBeyPMT9urHA
  7.1304 +ahzjaVCRTxfM0XtZISa22YxSo07tRt6nOkOd7LQzCRs/tV9kV7lJkcjsNimhL2iVYfj9hx/Owi4D
  7.1305 +6GGwUz84dx0NlzzcTiHcRzBtqIkTPqYPU+gxXX6/VLVdZZ+gZsvYJCA12bqE7eQdTdzavwb3ZCC8
  7.1306 +/UHeh8WIcLaSs5uJpL1lZFPs6uRg3+BrxMRuOfs1PipeUKESzGSW1kgrdvSwwmxRZzNKx1cS7Lku
  7.1307 +B8XyENox5nTTIo2XYkid55jq0NxI2ZDbuNTeTlHmWIAo6mR+tEzmQv5WxymGkXKxAFxwr0S/inh4
  7.1308 +yniIt7zpzYVpSs7qMqm2QIJY5XqrifbHnYbTLU906CHJuwpMQNwxPxYfcdr4ngk3N+QywaifYMdJ
  7.1309 +YpyHHcxeIHIXPYf3WT7BUSdUxzlmpLrbwPQ4aI+QA4ABAIX5D0Y6U+S/kfTK3c+iNXeJilrSI6Ub
  7.1310 +2ebkcSCU4Qgja/5NP31GdHlrB5bL3Vgu92O5bGO57MVy6WO53I+lKxK4sDZJYiShL1HSzqL3FmS4
  7.1311 +OQ4e5iyerbgd1vdhHR9AFIUJ6IxMcZmrl0nh7SQCQmrb2d+kh02BRcKFg2XOKVcNErkf90x08GgK
  7.1312 +lJ3OVK6hO/NUjM+2q8jE73sURVQONKXuLG/zuIojTy6WaT4FsbXojhsAY9GuN+HcXHY7mXI2sWWp
  7.1313 +Bpf/9en7D++xOYIamN106oaLiIYFpzJ8GpdL1ZWmJtgogB2ppV/3Qd00wIMHZnJ4lAP+7y0VFCDj
  7.1314 +iA1tiOeiAA+Ayn5sM7c4Jgxbz3UVjX7OTM57GydikFWDZlI7iHR6efn29NPpgFJMg/8duAJjaOtL
  7.1315 +h4uPaWEbdP03t7mlOPYBoda5lMb4uXPyaN1wxP021oBtub3PrlsPXjzEYPeGpf4s/62UgiUBQkU6
  7.1316 +2fgYQj04+PlDYUKHPoYRO9Vh7k4OOyv2nSN7joviiH5fmrs9gL+3hjHGBAigXaihiQyaYKql9K15
  7.1317 +3UNRB+gDfb0/HIK1Q692JONT1E6ixwF0KGub7Xb/vH0BNnpKVq/Pvjt/f3H++vL00/eOC4iu3IeP
  7.1318 +Ry/E2Q+fBZUjoAFjnyjGnfgKC1/AsLiHWcQ8h381pjfmdcVJSej19uJC7wys8TgD1reizYngOVfN
  7.1319 +WGico+Gsp32oy10Qo1QHSM65EaoOoXMlGC+t+cyCynUNLB1HmaKzWuvQS58HMueGaBs1AumDxi4p
  7.1320 +GARXNMErqlSuTFRY8o6TPkvTg5S20bYOIaUcVGd32tlvMdl8LzFHneFJ01kr+qvQxTW8jlSRJhDJ
  7.1321 +vQqtLOluWI3RMI5+aDdUGa8+Deh0h5F1Q571TizQar0KeW66/6hhtN9qwLBhsLcw70xSNQLV6GIt
  7.1322 +lQixEe8chPIOvtql12ugYMFwY6nCRTRMl8DsYwiuxSqBAAJ4cgXWF+MEgNBaCT8BfexkB2SOxQDh
  7.1323 +m/X88O+hJojf+pdfeppXZXr4D1FAFCS4ciXsIabb+C0EPpGMxNmHd6OQkaNKUPH3GkvAwSGhLJ8j
  7.1324 +7VQuwzu2k6GS6UKXM/j6AF9oP4Fet7qXsih1937XOEQJeKKG5DU8UYZ+IVYXWdhjnMqoBRqr2y1m
  7.1325 +eErM3fY2nwPxcSXTVBdEn7+9OAPfEQvuUYJ4n+cMhuN8CW7Z6lovPsXWAoUbuvC6RDYu0YWlTf15
  7.1326 +5DXrzcyiyFFvrw7ArhNlP7u9OqnOMk6Ui/YQp82wnJLzCLkZlsOsLHN3txnS2W1GdEfJYcaYXJZU
  7.1327 +NelzBnA0PY05MIKICYv6TbKZ9y6TrDJlcmkyA20KihfU6hhEBUmMJ9eI//KM0715qcyBF3hYbMtk
  7.1328 +uaowpQ6dIyq2x+Y/nH6+OH9P1esvXja+dw+LjikeGHPpwgnWpWHOA764tWbIW5NJH+fqVwgDdRD8
  7.1329 +ab/imogTHqDTj9OL+Kf9ik8cnTjxIM8A1FRdtIUEwwCnW5/0NBLBuNpoGD9u3VmDmQ+GMpJ4wEGX
  7.1330 +F7jz6/KjbdkyKJT9MS8fsVexKDQNh6azWwfV/ug5LgrcXJkP+xvB2z4JM58pdL3pvNlVceV+OrKI
  7.1331 +hx8Bo25rfwxTk9RpqqfjMNsubqHgVlvaXzInY+q0m2UoykDEodt55DJZvyrWzZkDvdrdDjDxjUbX
  7.1332 +SGKvQh/8kg20n+FhYondiVZMRzo7QaYA8xlSHxGpwZNCuwAKhEpOh47kjkdPX3hzdGzC/XPUugss
  7.1333 +5PegCHUBKB0syEvgRPjyG7uP/IrQQlV6LELHX8lkltvqJPxsVuhbPvfn2CsDlMpEsSvjbCmHDGts
  7.1334 +YH7pE3tHIpa0rccxV0mrWkJzN3iodzsYvCsW/bsnBrMWH3Ta3chtWxv51MEGvccPfAhlvAHtXtTV
  7.1335 +kNdq52YBNtdbsMMQkyS/hTvodQ96Ghb6Xb/17OHgh4ll3Etrr1pHW0L7QvuVsxICpkrRZoljhY2H
  7.1336 +6BrmxgaeNFZ4YJ/qihH7u+e8kFPl6sJlFFyo3gwHukEr1B/wyRU+uZdQZXRzsEK/m8tbmebgFkHE
  7.1337 +hYXvv9rC91FkUx29NUF/BoKX28ttP3r0pkHu2BTno+OkCljIKJPVEWLUm5C5B7kGH1z2X3TQEGc3
  7.1338 +5Me++fl8LN68/xH+fy0/QOSD59fG4h+AiXiTlxAB8hlKOtyOpf0Vh3Z5rfCQG0GjzQS+BwBdqkuP
  7.1339 +2rhxoc8c+IcNrBYTWGdZrvnyCUCR50jnihsbbirp4bc56tN1Fo0j17c0A/0SybD7AAQeGjjSLaNV
  7.1340 +tU5RnTupjGZNrwYX52/O3n88i6o75Hbzc+CkOvwqHZyR3sgtcdNqLOyTWY1Prh2/9nuZFj1urY4M
  7.1341 +zWEKjAxFCMFDYaNBvtsgthFAXGJ4L4rtPJ9F2BJ4n89vVRvwc0dOEHivHfaMIMIajvRWV+Ns42Og
  7.1342 +hvilrZcG0JD66DlRT0IonuJBIn4cDfot5VhQ/hn+PL3ZzN30tT4RQhNsY9rMeuh3t6pxxXTW8Fxm
  7.1343 +ItRO7EqYc4JpEqv1dOaeH/uQCX07BSg92o+Qi7hOKyEzEGEKxumaAND97pEvlhPmFrY4dA6K0inp
  7.1344 +Jt4qpyImVmKAow7opDNunFBmD2LlH+IbthB4Fk3UfKgVoBOiFOHkTldVz1Ysxxy0EAF7CgQ2Sfby
  7.1345 +RdghMg/KkeyscTVhnujYMUZLWen584Ph6Op5Y+wpezzzDnzOCrCDLqccgA4tnj59OhD/cb9/wqhE
  7.1346 +aZ7fgOMEsPvCVnFBr3d4FnpydrW6vrd5EwFLzlbyCh5cU5bbPq8zSiHu6UoLIu1fAyPEtQktP5r2
  7.1347 +LUvNybWSN4S5BW8saRPyU5bQHTSYApKocvVVPpgeMgJFLAm6IYzVLElCTifAemzzGs9qYTpQ84u8
  7.1348 +A45PEMwY3+JOFgfDK/QBqbDSco9F50QMCPCACp14NDrsSqeVAM/J5VajOTnPkqo5Z/DM3eTUh7or
  7.1349 +e7WM5isRb1AyzDxaxHCO/Xms2vjA+V4W9WKKfHblJgZbs+TX9+EOrA2Sli8WBlN4aBZplstyZowq
  7.1350 +rlgySyoHjGmHcLgz3ahDBigKelAagIYnwzC3Em3ffmHXxcX0A+33HpqRdJlPZW8p4iROnLWq3aKo
  7.1351 +GZ/SRZaQlm/NlxGM8p7Sz9of8MYSX+jkJxaZe5cpuMfd6kxfksB1Fs3NCQCHLuaxCtKyo6cjnNug
  7.1352 +LHxmWh1uNHcqODXxGEQTbrdJWdVxOtEH+SfouU3sBrjG0x6T2nsA0Pos4Pbn4BAf6pJu8B1MNQzS
  7.1353 +EysyTcn+iVjoJELkHj3yT+kUOfp6Lzw9jqnpZ3wRgKPBseWX5vDKQ1S+OULROX3gYjmm2qNw1K6o
  7.1354 +7LTCfQ5TIm+d7HYc8KghW7B8h31WbPFOHpjWk3lE/0LfkaPLFHBj6tGDp8mUBgv7Co/v76srATH+
  7.1355 +W4OgLBI5P3yiEDvG+Y9C1VAMddxA4REzDOnuCQL5ZWsnzykv5NrfXds3HaBff7UPrKuCewufac/E
  7.1356 +V8v6aJtbidxs2uDnwHrEK3C6UW/MzWFkrZb43CbqEDaI9qy5qVdpH5mB1w+f8p4JP2BHNMTBNHe4
  7.1357 +8rqPVha/faRqGgW/i0q6Vz+t0AnGUtFVzG9QmdXFsQ0V+TBfRmn2oVtAhJ/qpre0Psa7j4jRq5tw
  7.1358 +3/S5/7656xaBnbnZP+vM3T9C49JA993NL300YAddE+JBVbkWo8mfI7pjvbXbn6LSn4W9hZEzVcSD
  7.1359 +GrWxZsl1PHO/Y4HBIV/i6B6HClyQZtVbc+qcD2uzc5eTu9zMm6n43J6QpB3yuWYvNud0pc+Ea64m
  7.1360 +crlUkxhvhJqQD0j1AR3jbryKd3QbkIzV1jgDeOcCgDCsoiu53GJNWHXwM/lmSt5edw7XCxqaitCc
  7.1361 +qjaVzDm2154HgIs4pqf+JnPEZWmDVGI2RtVlUYKzNtD3F/K+b1+pXAPUxJfrWN0Y1E2Psb7ODofg
  7.1362 +YgNzhIozCewAetQBQvDJCudmF67znEzsO+CXZ81R0WRsGUJm9VqWcdXckuDvLyXiW2cEOjiHC+xE
  7.1363 +kI3YtTjFRSyx/OEghTGc/f6ldo4832/P+dCRVWkPZyvqoZMTjzl66ki54ebkzt6S5N7OMadrMSle
  7.1364 +5Ns1hG3WcJ+9GQKWwlz5Q4pQh3T8Vl9DwvfTcc4Jq+ocPgK5d4+t+NWNVmexw2DRcJ65iqF77wSe
  7.1365 +fCRD23edVIcLuhdH+czQjO/rDcssnd2EHY0tFU+4Ra/iaUYbNYEOFiLdE+j4xaaPDHQ8+A8MdPTl
  7.1366 +X2BNND5aH/SWn94TEbGacG/SahgB+kyASLhh0rqHydjDoVvMCeFKcjewl1GyznROiBgzgRzZvWKF
  7.1367 +QPCNWcqtfPNutDHj9kUivnTR4+8uPrw+vSBaTC5P3/zn6Xe0zY9ZvZbNenAkmOWHTO1Dr6zQjQr1
  7.1368 +1mzf4A22PVfTcW28htB539nW6oHQfw6ib0Hbisx9vatDp5682wkQ3z/tFtRdKrsXcsf50rXL7oZs
  7.1369 +q/4v0E+5WMv8cvbWzCOTU2ZxaBLG5n2T49My2kmB7Fo4p2yqq060U6ovM9uRnhnZ4j1aAUztIX/Z
  7.1370 +zJ6pxLb5I3ZU2leEU8UhnmIxNwGAFM6kcyEV3UXFoCr/LvISlF2MOxTsMI7tvZ7UjrOYyl5Yi7sU
  7.1371 +MxkZgnjHSAbd+bnCPpfpDioEASs8fd0SI2L0n877272yJ0pcHdKBtUNUNtf2F66ZdnJ/TnBHrLL3
  7.1372 +liiz5Y27AdB4UafuLpft0+lAzh8lTfOFUyENmu8I6NyIpwL2Rp+JFeJ0K0KIEvVWDhZdER31nUMO
  7.1373 +8mg3HewNrZ6Jw13HmdzjPEI8391w3joxpHu84B7qnh6qNodGHAuMdT+7zimJbwkyZ90FXVTiOR+4
  7.1374 +26Ovx4Svt1fPj23KFvkdX7vXYCDtB45hv2pOBuy9GsvpTbxSjqn+A4uNRm3w1wOHNRdid4DTqXPe
  7.1375 +EQSZ7TiGNPDe99dGmB7enb2DNqKW745hQmL4RI1oUk5luMbdPhl1JtuorC4MLnK/H0ZH+wEohNLv
  7.1376 +m+CHb2MB9fxMx4PTmu4TtA4nHg115IEKHXxe4B7G62uwa3eno2kP6k4l//agADdo855ebxBr9hq4
  7.1377 +lZfo2G0L2jNveGCH7edDfv39nz+gf7ckxnZ/sc+htq1e9h4sYScWi6hw87pFIfM4AusCCnNIahrr
  7.1378 +b42E4+H9howONzVTQ65Ah4/qsvCuUAosyImdaMtvjUHwf71Zz9M=
  7.1379 +""".decode("base64").decode("zlib")
  7.1380 +
  7.1381 +##file ez_setup.py
  7.1382 +EZ_SETUP_PY = """
  7.1383 +eJzNWmuP28YV/a5fwShYSIJlLt8PGXKRJi5gIEiDPAoU9lY7zxVrilRJyhu1yH/vmeFDJLVU2iIf
  7.1384 +ysDZXXJ45z7PuXekL784nqt9ns3m8/kf87wqq4IcjVJUp2OV52lpJFlZkTQlVYJFs/fSOOcn45lk
  7.1385 +lVHlxqkUw7XqaWEcCftEnsSirB+ax/Pa+PuprLCApScujGqflDOZpEK9Uu0hhByEwZNCsCovzsZz
  7.1386 +Uu2NpFobJOMG4Vy/oDZUa6v8aOSy3qmVv9nMZgYuWeQHQ/xzp+8byeGYF5XScnfRUq8b3lquriwr
  7.1387 +xD9OUMcgRnkULJEJMz6LooQT1N6XV9fqd6zi+XOW5oTPDklR5MXayAvtHZIZJK1EkZFKdIsulq71
  7.1388 +pgyreG6UuUHPRnk6HtNzkj3NlLHkeCzyY5Go1/OjCoL2w+Pj2ILHR3M2+0m5SfuV6Y2VRGEUJ/xe
  7.1389 +KlNYkRy1eU1UtZbHp4LwfhxNlQyzxnnluZx98+5PX/387U+7v7z74cf3f/7O2BpzywyYbc+7Rz//
  7.1390 +8K3yq3q0r6rj5v7+eD4mZp1cZl483TdJUd7flff4r9vtfm7cqV3Mxr8fNu7DbHbg/o6TikDgv3TE
  7.1391 +Fpc3XmNzar8+nh3TNcXT02JjLKLIcRiRsWU7vsUjL6JxHNBQOj4LRMDIYn1DitdKoWFMIuJZrvB8
  7.1392 +y5GURr4QrrRjzw5dn9EJKc5QFz/ww9CPeUQCHknmeVZokZhboRM6PI5vS+l08WAAibgdxNyhIghs
  7.1393 +SVyHBMJ3hCcjZ8oid6gLpa7NLMlCN45J4PphHIc+IzyWPrECO7oppdPFjUjEcJcHgnHHcbxQ2mEs
  7.1394 +Q06CIJaETUjxhroEjuX5xPEE94QtKAtDKSw3JsQTgQyFf1PKxS+MOsSOfOgRccKkpA63oY/lUpfa
  7.1395 +zHtZChvlC3WlQ33fjXmAuIYy9AgPY9uBIBJb0YRFbJwvsIcLDk8GIXe4I6WwPcuK3cCTDvEmIs1s
  7.1396 +a6gMgzscQn3uEsvxA88PEB9mu5FlkdCKrdtiOm38kONFxCimkRWGDvNj4rsk8lyX+JxPeqYW47di
  7.1397 +uPACwiL4Mg5ZFPt+6AhfRD7SUdCIhbfFBJ02kUAlESGtAA5ymAg824M0B0bC4RPRBqgMfeNQIghq
  7.1398 +2HY53kcZOZEIKfGpT6ARF7fFXCLFAzeWMbUgzGOe48Wh5XpcMEcwizmTkbKHvgk8FnvSpTIkIbLQ
  7.1399 +FSxyhUUdhDv0YurcFtP5hkoSO7ZlUY4wcdQEJAnOXQQ+8KwomBAzwhlpWYFHZUCIQ0NuQS141kNi
  7.1400 +W5EdMmcqUCOcCezAjh0hmOtLLxSImh0wHhDbgVQnnJIywhlpRwAogC+XSBXi+DGLIUXaPKRhJCfQ
  7.1401 +io1wRliCh14QOSyOIyppCE9HFrLXQsxDeyrY7jBIhAppB5JzGOb7vu1Fns1C4BePozjwp6SM0Ipa
  7.1402 +NLZdmzBCXceCM4BzofQ85gMoQlvelNJZhCSR2DPgnqTSRUVRGXsBs+AqoJ6YShhvaFGk0BrA7zqM
  7.1403 +05iFDmXSA3w5gXQiIqfQyh9aJEQseWRBHRQkMla6ApjuhwAMHtnBVKT9oUVEAqu4BKvYoWULAeeG
  7.1404 +ICefMhAeCaZQxh/FKOKuDAAIHmOERKHtIXG4G1LGuMt9PiElGFqEgonA8pFtB2CiKPJCByLAmL4X
  7.1405 +o7SngDMYsRvzAyL9kMK/6B5QDYEFQzzPRYH5ZAobgqFF1JERCX0HZA/YpS5I2kKoufAlWgnfnZAS
  7.1406 +juDOQoxkTDhzSWD7wrdtH2WIliICBE7mSzhiAhLJ2PfAAhxYbkkahEza0kEY8MiZqoBwaJEHjiXA
  7.1407 +W4mWAQXouZ5t25KLyLXxL5zSJRp1Q5bqhZwYHok5+EOlIAA8ci3VWFm3pXQWMUrcCNiAnsOLXGap
  7.1408 +nEW2wdkMzDJJA9HQIjt07BAgh0DHnNm+5ccW8SPqCtR57E9FOh5aBN2ZZ6GZsZWHqRcHwmOSCiuC
  7.1409 +rcyainQ8QgYkGRo7cKsbRTwAOhEhrADgxQLXm+rvGimdRVIgtK7wiR1S22EIE/M9m4bgXjC/mGKS
  7.1410 +eMhHjKBsbKlQkziCA5js2AWzhdSPHfQ4kPLrrDcRYLwpZ1Vx3tQD156U+zSh7byF3n0mfmECo8Z7
  7.1411 +feedGomatXjYXzfjQhq7zyRN0O2LHW4todMuwzy4NtQAsNpoAxJptPfVzNiOB/VDdfEEs0WFcUGJ
  7.1412 +0C+ae/FLfRfzXbsMcpqVX2w7KR9a0Q8XeerC3IVp8O1bNZ2UFRcF5rrlYIW65sqkxoJmPrzDFEYw
  7.1413 +hvEvDGP5fV6WCU174x9GOvx9+MNqfiXsrjNz8Gg1+EvpI35JqqVT3y8Q3CLT7qodOhoO9aJmvNqO
  7.1414 +hrl1p9aOklJsewPdGpPiDqPqNi9NdirwW51M3QtcpOS8tf1ZEySMjV+dqvwAPzBMl2eMohm/78zu
  7.1415 +nRSouf5APiGWGJ4/w1VEOQjOU6YdSbWvx/nHRulHo9znp5SraZbUvu5Layfz7HSgojCqPakMDMKd
  7.1416 +YC1LTcCZ8q4hMfV2Sp0yrl8RxuPAEY+GGmmXz/uE7dvdBbRWRxO1PGNxv1iZULL20qPaUsnpHWPs
  7.1417 +RTE4IHlOMHPTSyYIvkZG1gmuVc5y+CMtBOHni/rY473sqafdrrdrzia0mKrRUkujQqvSOESfWLA8
  7.1418 +42Xtm1aNI0GiKKfCI6qskipB6LKn3nlGHfHG/jwT+jyhPhvhtV5wap4qH754PqK0bA4bRCNMn+UU
  7.1419 ++Qk7iVqVus6IcRBlSZ5EfcBxKbrHR50vBUlKYfx4LitxePeL8ldWByIzSIV79ckGoQpalPEqBZUx
  7.1420 +9amH2Wao/vlMyl2NQrB/ayyOn552hSjzU8FEuVAIo7Y/5PyUilKdkvQAdPy4rglUHUceNG5bri5I
  7.1421 +olJueymaXl02HhuVYFt261GhXTCgLRITnhVFtbTWapMeyDVA3e30pn+6Q9tjvl0TmJ0G5q2SUQcI
  7.1422 +wD6WNXCQfvgCwncvtYDUd0jz6HqHgWizSa7l/KLx2+38VeOq1ZtGdl+FoYC/1Cu/zjOZJqyCazZ9
  7.1423 +9O9H/r9F+/lP+0v2T+T78u32rlx1tdzWsD7K/JgNAX/OSLaoVEl1JQLMUMd3ukaa4zpVLacsQyqb
  7.1424 +xvepQIa0y6/kqRpSpQwAErCl1VAmRQlHnEpVDgtIOLehN17/3FN+YY7kfcw+ZsuvT0UBaYDzWsBd
  7.1425 +MeKtFVjrksvCJMVT+cF6uM1ZOn5pKYYxQKIPw7nuV9qHUZ0+qFe+hLUayfNPA1Ev5eB01nyToCQS
  7.1426 +elIM/l1e/SkHL9zO55ppXyrr35tuVfGjPAc8+80LpKrLmFxIwUhzVrckGj5rG5KqPiHWLcb/KcnW
  7.1427 +EK0+A2hJ9rc4Vt1Tu14TbI37jxfOnODFvGbDlgwVqbDqRNKLEQ3JDImk/YihANdQB9m6RwqldZ61
  7.1428 +/erW6IHZ67sSvfddqVrveb9wRkfgda5Cbp87lM+MV8MWsSSfBbTfoiWvSeHveZItWwppl9biyoIp
  7.1429 +cbpP/g5s3rbWCqra11GkZVUua7GrjSqwrz7niUqgoyCKL1t1yq4+BniuLp2KHIKUN8rWS2n+NFil
  7.1430 +mnEVl+G76sJK85kU2VL5+fXvd9WfkDTA2iB5+VKW3+mUUJ+cLMVnkak/YM4Rys72Ij2qvu99nW29
  7.1431 +3qNLFTQnKv/VZztL5YoZKGFtAF1m6tYB5ZwJOBKvoA5V5wuEFs8KjwnG2bLUb/c5QCO4OWu2BHQ3
  7.1432 +Pc5lR6jM22w2Z7MlQExslIe1mANhe9Vu8VzUxLRHeKFE9ZwXn5pN18axZpecVqT5XE4hhUaJu3I2
  7.1433 +UygCDzDdtesFkHypxKZyCtGwVd8Ac/V7RhFJsb5KmR7oXjVUOsvWqpquXkNHoZO1StRk2TROqRDH
  7.1434 +N/WP5aj3GmZnC8OaF8u53mLEe7rkGnww8TM/imx5texL4wc0/ffPRVIBfBBj+Fe328DwT2v10eCz
  7.1435 +ip5qF1ihyhDQyPKiOOnkSMVImI57Pz1UF14Jvb7FxPZqPmabGsJhgKkGkuVqqHGNItqaGivW82c6
  7.1436 +hzvxwNR21GN49xKGQTUUbsYQgA02eheW5qVYrq4goqw2Wmj/ecNmLWhBwVT90sLW7D+5FH8fkOlL
  7.1437 +NCyf11OMfeHc97c+NNUc+w6tVbOqJYiXmunRh9G3Oul6eOiw+kriZc3tAUNP6tZ1SzYcIwZThI6Z
  7.1438 +Ko3e7MDywwGGmoMesj3OIc1A1l5NjLSLU3CB9vPqlTpteVjpNH0Wi0KntTAUjf9mqihLlZ9HXKXU
  7.1439 +vuYQLDplmAA/LTuzhg1n0m/czd2u8dZuZ2wxElqmZdqL/3pE+CsAXoOrmotpmacCtToxGrdNP8ik
  7.1440 +buyvGvpCHPLPGm91JOrvPOgJGMxRAXrT38DdUac+2ZI3RfWPYbPSm7z63c71MPgfDHT4eaP/Hk1t
  7.1441 +m+ls/59T8laZdYJ/U8pVNr9Ud225PQxndu1sa4XEh1WK/RE4pjNFPXk5Q9Uuv5MDOvW15jemsDrN
  7.1442 +5z9etUXzdYsoc4DgkyaiQh3/IgnRJF0Sev6CvMXyB7RT8/bbOebxPJw+5/X3bq6/mmKuFs2x5rHj
  7.1443 +p3aEKS/w/LN+aqgSoackrV7X58QQ+aSGu7NC5H4WF838o3qt9ly5E3txiO65L921+lOtWF66ai2k
  7.1444 +5UJNmouCLi7PumNm9e5Dc0QtW1J98ZhadmRXj4A1RX+Yqz/uig3+rYEVGB+aTrNuyNqNTJDvoVyu
  7.1445 +HrqXzRIWd9R5VEPFfF5PCjVJ9x2DCGCErNqJQX+faNveNZ9EVRetur/sT+c73THsdk3Wdy5pZKwN
  7.1446 +7ZY3TUvUOuDN2NgDqTANbqGnWQpSsP1y/jHrfx/oY7b88LdfH16tfp3r9mTVH2P02z0segGxQeT6
  7.1447 +G1mpIRQKfDG/LtIWEWtV8f8PGy3Y1K330l49YAzTjnyln9YPMbri0ebhZfMXz01OyKY96lTvOWAG
  7.1448 +M1o/breL3U4V7G636D4FSZVEqKlr+K2j6bD9+4P9gHdev4az6lLp0VevdrrlzubhJV7UGHGRqRbV
  7.1449 +178BYnMUkw==
  7.1450 +""".decode("base64").decode("zlib")
  7.1451 +
  7.1452 +##file distribute_setup.py
  7.1453 +DISTRIBUTE_SETUP_PY = """
  7.1454 +eJztG2tz2zbyu34FTh4PqYSi7TT3GM+pM2nj9DzNJZnYaT8kHhoiIYk1X+XDsvrrb3cBkCAJyc61
  7.1455 +dzM3c7qrIxGLxWLfuwCP/lTs6k2eTabT6Xd5Xld1yQsWxfBvvGxqweKsqnmS8DoGoMnliu3yhm15
  7.1456 +VrM6Z00lWCXqpqjzPKkAFkdLVvDwjq+FU8lBv9h57JemqgEgTJpIsHoTV5NVnCB6+AFIeCpg1VKE
  7.1457 +dV7u2DauNyyuPcaziPEoogm4IMLWecHylVxJ4z8/n0wYfFZlnhrUBzTO4rTIyxqpDTpqCb7/yJ2N
  7.1458 +dliKXxsgi3FWFSKMV3HI7kVZATOQhm6qh98BKsq3WZLzaJLGZZmXHstL4hLPGE9qUWYceKqBuh17
  7.1459 +tGgIUFHOqpwtd6xqiiLZxdl6gpvmRVHmRRnj9LxAYRA/bm+HO7i99SeTa2QX8TekhRGjYGUD3yvc
  7.1460 +SljGBW1PSZeoLNYlj0x5+qgUE8W8vNLfql37tY5Tob+vspTX4aYdEmmBFLS/eUk/Wwk1dYwqI0eT
  7.1461 +fD2Z1OXuvJNiFaP2yeFPVxcfg6vL64uJeAgFkH5Jzy+QxXJKC8EW7F2eCQObJrtZAgtDUVVSVSKx
  7.1462 +YoFU/iBMI/cZL9fVTE7BD/4EZC5s1xcPImxqvkyEN2PPaaiFK4FfZWag90PgqEvY2GLBTid7iT4C
  7.1463 +RQfmg2hAihFbgRQkQeyF/80fSuQR+7XJa1AmfNykIquB9StYPgNd7MDgEWIqwNyBmBTJdwDmmxdO
  7.1464 +t6QmCxEK3OasP6bwOPA/MG4YHw8bbHOmx9XUYccIOIJTMMMhtenPHQXEOviiVqxuhtLJK78qOFid
  7.1465 +C98+BD+/urz22IBp7Jkps9cXb159ensd/HTx8ery/TtYb3rq/8U/ezlthz59fIuPN3VdnJ+cFLsi
  7.1466 +9qWo/LxcnygnWJ1U4KhCcRKddH7pZDq5urj+9OH6/fu3V8GbVz9evB4sFJ6dTScm0Icffwgu3715
  7.1467 +j+PT6ZfJP0XNI17z+U/SHZ2zM/908g786LlhwpN29LiaXDVpysEq2AN8Jv/IUzEvgEL6PXnVAOWl
  7.1468 ++X0uUh4n8snbOBRZpUBfC+lACC8+AIJAgvt2NJlMSI2Vr3HBEyzh35m2AfEAMSck5ST3LodpsE4L
  7.1469 +cJGwZe1N/PQuwu/gqXEc3Ia/5WXmOhcdEtCB48rx1GQJmCdRsI0AEYh/LepwGykMrZcgKLDdDcxx
  7.1470 +zakExYkI6cL8vBBZu4sWJlD7UFvsTfbDJK8EhpfOINe5IhY33QaCFgD8idw6EFXweuP/AvCKMA8f
  7.1471 +JqBNBq2fT29m441ILN1Ax7B3+ZZt8/LO5JiGNqhUQsMwNMZx2Q6y161uOzPTnWR53XNgjo7YsJyj
  7.1472 +kDsDD9ItcAU6CqEf8G/BZbFtmcPXqCm1rpjJiW8sPMAiBEEL9LwsBRcNWs/4Mr8XetIqzgCPTRWk
  7.1473 +5sy0Ei+bGB6I9dqF/zytrPAlD5B1/9fp/wGdJhlSLMwYSNGC6LsWwlBshO0EIeXdcWqfjs9/xb9L
  7.1474 +9P2oNvRojr/gT2kgeqIayh3IqKa1qxRVk9R95YGlJLCyQc1x8QBLVzTcrVLyGFLUy/eUmrjO93mT
  7.1475 +RDSLOCVtZ71GW1FWEAHRKod1VTrstVltsOSV0BszHkci4Tu1KrJyqAYK3unC5Py4mhe748iH/yPv
  7.1476 +rIkEfI5ZRwUGdfUDIs4qBx2yPDy7mT2dPcosgOB2L0bGvWf/+2gdfPZwqdOrRxwOAVLOhuSDPxRl
  7.1477 +7Z56rJO/yn77dY+R5C911acDdEDp94JMQ8p7UGOoHS8GKdKAAwsjTbJyQ+5ggSrelBYmLM7+7IFw
  7.1478 +ghW/E4vrshGtd005mXjVQGG2peSZdJQvqzxBQ0VeTLolDE0DEPzXNbm35VUguSTQmzrF3ToAk6Ks
  7.1479 +raIkFvmb5lGTiAorpS/tbpyOK0PAsSfu/TBE01uvDyCVc8MrXtel2wMEQwkiI+hak3CcrThoz8Jp
  7.1480 +qF8BD0GUc+hqlxZiX1nTzpS59+/xFvuZ12OGr8p0d9qx5NvF9LlabWYha7iLPj6VNn+fZ6skDuv+
  7.1481 +0gK0RNYOIXkTdwb+ZCg4U6vGvMfpEOogI/G3JRS67ghiek2enbYVmT0Hozfjfrs4hoIFan0UNL+H
  7.1482 +dJ0qmS/ZdIwPWykhz5wa601l6oB5u8E2AfVXVFsAvpVNhtHFZx8SAeKx4tOtA87SvERSQ0zRNKGr
  7.1483 +uKxqD0wT0FinO4B4p10Om38y9uX4Fvgv2ZfM/b4pS1gl2UnE7LicAfKe/xc+VnGYOYxVWQotrt0X
  7.1484 +/TGRVBb7AA1kA5Mz7PvzwE/c4BSMzNTYye/2FbNfYw1PiiH7LMaq1202A6u+y+s3eZNFv9toHyXT
  7.1485 +RuIo1TnkroKwFLwWQ28V4ObIAtssCsPVgSj9e2MWfSyBS8Ur5YWhHn7dtfhac6W42jYSwfaSPKTS
  7.1486 +hdqcivFxLTt3GVTyMim8VbTfsmpDmdkS25H3PIl72LXlZU26FCVYNCdTbr0C4cL2HyW91DFp+5Cg
  7.1487 +BTRFsNseP24Z9jhc8BHhRq8uskiGTezRcuacODOf3Uqe3OKKvdwf/IsohU4h236XXkVEvtwjcbCd
  7.1488 +rvZAHdYwzyLqdRYcA/1SrNDdYFszrBuedB1X2l+NlVTtazH8RxKGXiwioTYlVMFLikIC29yq31wm
  7.1489 +WFZNDGu0xkoDxQvb3Hr9W4DqgK2fXnLsYxm2/g0doJK+bGqXvVwVBcmet1hk/sfvBbB0TwquQVV2
  7.1490 +WYaIDvalWquGtQ7yZol2do48f3Wfx6jVBVpu1JLTZTijkN4WL631kI+vph5uqe+yJVGKS+5o+Ih9
  7.1491 +FDw6odjKMMBAcgaksyWY3J2HHfYtKiFGQ+laQJPDvCzBXZD1DZDBbkmrtb3EeNZRC4LXKqw/2JTD
  7.1492 +BKEMQR94NMioJBuJaMksj023y+kISKUFiKwbG/lMJQlYy5JiAAG6RB/AA35LuINFTfiuc0oShr0k
  7.1493 +ZAlKxqoSBHddgfda5g/uqslC9GbKCdKwOU7tVY89e3a3nR3IimXzv6tP1HRtGK+1Z7mSzw8lzENY
  7.1494 +zJmhkLYly0jtfZzLVtKozW5+Cl5Vo4HhSj6uA4IeP28XeQKOFhYw7Z9X4LELlS5YJD0hsekmvOEA
  7.1495 +8OR8fjhvvwyV7miN6In+UW1Wy4zpPswgqwisSZ0d0lR6U2+VohNVAfoGF83AA3cBHiCru5D/M8U2
  7.1496 +Ht41BXmLlUysRSZ3BJFdByTyluDbAoVDewREPDO9BnBjDLvQS3ccOgIfh9N2mnmWntarPoTZLlW7
  7.1497 +7rShm/UBobEU8PUEyCYxNgTkDIhimc+ZmwBD2zq2YKncmuadPRNc2fwQ6fbEEAOsZ3oXY0T7JjxU
  7.1498 +1myzCk27uCHvDR4rVKM9SwSZ2OrIjE8hyjr++7ev/eMKj7TwdNTHP6PO7kdEJ4MbBpJc9hQliRqn
  7.1499 +avJibYs/Xduo2oB+2BKb5veQLINpBGaH3C0SHooNKLvQnepBGI8r7DWOwfrUf8ruIBD2mu+QeKk9
  7.1500 +GHP369cK646e/8F0VF8IMBrBdlKAanXa7Kt/XZzrmf2YZ9gxnGNxMHT3evGRt1yC9O9Mtqz65VHH
  7.1501 +ga5DSim8eWhurjtgwGSkBSAn1AKRCHkkmzc1Jr3oPbZ819mcrnOGCZvBHo9J1VfkDySq5huc6Jy5
  7.1502 +shwgO+jBSlfViyCjSdIfqhkes5xXqs624ujIt3fcAFPgQxflsT41VmU6AsxblojaqRgqfut8h/xs
  7.1503 +FU3xG3XNNVt43qD5p1r4eBMBvxrc0xgOyUPB9I7Dhn1mBTKodk1vM8Iyjuk2vQSnKhv3wFZNrOLE
  7.1504 +nja6c9Vd5ImMNoEz2EnfH+/zNUPvvA9O+2q+gnS6PSLG9RVTjACGIO2NlbZt3dpIx3ssVwADnoqB
  7.1505 +/09TICLIl7+43YGjr3vdBZSEUHfJyPZYl6Hn3CTdXzOl53JNckElLcXUY27YImzNHN1YGLsg4tTu
  7.1506 +nngEJqcilfvkUxNZEXYbVZHYsCJ1aFN1fhAW+NLTOXffVQFP0vYVTm9Aysj/aV6OHaDV80jwA35n
  7.1507 +6MO/R/nLSD6a1aVErYM8nBZZ3ScB7E+RJKvqNifazypDRj5McIZJyWAr9cbgaLcV9fixrfTIMDpl
  7.1508 +Q3k9vr/HTGzoaR4Bn/Xy+TbodTndkQolEIHCO1SlGH/Z8uu9Cioz4IsffpijCDGEgDjl969Q0HiU
  7.1509 +wh6Ms/tiwlPjquHbu9i6J9kH4tO7lm/9RwdZMXvEtB/l3H/FpgxW9MoOpS32ykMNav2Sfco2oo2i
  7.1510 +2Xeyj7k3nFlO5hRmatYGRSlW8YOrPX0XXNogR6FBHUpC/X1vnPcbe8Pf6kKdBvysv0CUjMSDETaf
  7.1511 +n53ftFkUDXr62p3ImlSUXF7IM3snCCpvrMp8az4vYa/yHoTcxDBBh00ADh/WLOsK28yoxAsMIxKP
  7.1512 +pTFT54WSDM0skrh2HVxn4cw+zwencwYLNPvMxRSu4RGRpApLQ0mF9cA1Ac2Utwi/lfyx95B65Faf
  7.1513 +CfK5hcqvpbSjEZjbVKJ06GihuxyrjgqxjWvt2NhWaWdbDENq5EhVh8p+FXI6UDTOHfX1SJvt7j0Y
  7.1514 +P9ShOmJb4YBFhUCCJcgb2S0opHGrJ8qFZEolRIrnDObx6LhLQj+3aC79UkHdO0I2jDdkxCFMTGHy
  7.1515 +tvIxa+uf6fsf5XkvJtvgFUtwRr3yxJ64D7SFYj5iWJAbVx5Xce56V4gR37BVaRwkvfpw+QcTPuuK
  7.1516 +wCFCUMi+Mpq3ucx3C8ySRBbmdtEcsUjUQt2aw+CNJ/FtBERNjYY5bHsMtxiS5+uhoT6b7zwYRY9c
  7.1517 +GrRbt0Msqyhe0KGC9IWokOQL4wcitijz+zgSkXz9IV4pePNFi8poPkTqwl3qdYcauuNoVhz9wGGj
  7.1518 +zC4FhQ0Y6g0JBkTyLMR2D3SsrfJGONCygfpjf43SS8PAKqUcK/O6ntqSZRO+yCIVNOjO2J5NZXN5
  7.1519 +m68TXo8OtO/9fTSrVPVkRRrgsHlYS1PFuPC5n6R9GZOFlMMJlCLR3Zd/os71uxFfkYPuTUIPNJ8H
  7.1520 +vOnPG7efTd1oj+7QrOl8Wbo/Ous1/H0mhqLtZ/+/V54Deum0MxNGwzzhTRZuuhSuezKMlB/VSG/P
  7.1521 +GNrYhmNrC99IkhBU8Os3WiRUERcs5eUdnuXnjNMBLO8mLJvWeNpU7/ybG0wXPjvz0LyRTdkZXrFJ
  7.1522 +xFy1AObigd5fgpx5nvIMYnfk3BghTmM8vWn7Adg0MxPMz/03Lm7Y83baROOg+znWl2la7hmXkiuR
  7.1523 +rGTjfDH1px5LBV4cqBYYU7qTGXWRmg6CFYQ8ZqRLACVwW7IWf4byipG+R6z3111oQJ+M73rl2wyr
  7.1524 +6jSP8K0w6f+x2U8AhSjTuKroNa3uyE4jiUEJqeEFMo8qn93iBpz2Ygi+ogVIV4IIGV2jBkIVB+Ar
  7.1525 +TFY7ctATy9SUJ0REiq/c0WUR4CeRTA1AjQd77EqLQWOXO7YWtcLlzvo3KFRCFubFzvwNhRhk/OpG
  7.1526 +oGSovE6uARTju2uDJgdAH27avECLZZQP6AGMzclq0lYfsBL5Q4goCqRXOath1f8e+KUjTViPHnWh
  7.1527 +peIrgVIVg2P9DtLnBVSgkavW6LsyTdeCuOXjn4OAeJ8M+zYvX/6NcpcwTkF8VDQBfad/PT01krFk
  7.1528 +5SvRa5xS+duc4qNAaxWsQu6bJJuGb/b02N+Z+8JjLw0OoY3hfFG6gOHMQzwvZtZyIUwLgvGxSSAB
  7.1529 +/e50asg2ROpKzHaAUlLv2o4eRojuxG6hFdDH435QX6TZQQKcmccUNnl1WDMIMje66AG4WgturRZV
  7.1530 +l8SBqdyQeQOlM8Z7RNI5oLWtoQXeZ9Do7JykHG6AuE7GCu9sDNjQ+eITAMMN7OwAoCoQTIv9N269
  7.1531 +ShXFyQlwP4Eq+GxcAdON4kF1bbunQMiCaLl2QQmnyrXgm2x44UnocJDymGrue4/tueTXBYLLQ6+7
  7.1532 +kgpc8GqnoLTzO3z9X8X44cttQFxM918weQqoIg8CJDUI1LuURHcbNc/Ob2aTfwH3muVf
  7.1533 +""".decode("base64").decode("zlib")
  7.1534 +
  7.1535 +##file activate.sh
  7.1536 +ACTIVATE_SH = """
  7.1537 +eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9
  7.1538 +H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq
  7.1539 +DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs
  7.1540 +cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY
  7.1541 +G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T
  7.1542 +EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs
  7.1543 +wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG
  7.1544 +5eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/
  7.1545 +JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR
  7.1546 +huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx
  7.1547 +Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L
  7.1548 +Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw
  7.1549 +WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX
  7.1550 +LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2
  7.1551 +""".decode("base64").decode("zlib")
  7.1552 +
  7.1553 +##file activate.fish
  7.1554 +ACTIVATE_FISH = """
  7.1555 +eJydVm1v4jgQ/s6vmA1wBxUE7X2stJVYlVWR2lK13d6d9laRk0yIr8HmbIe0++tvnIQQB9pbXT5A
  7.1556 +Ys/LM55nZtyHx5RrSHiGsMm1gRAh1xhDwU0Kng8hFzMWGb5jBv2E69SDs0TJDdj3MxilxmzPZzP7
  7.1557 +pVPMMl+q9bjXh1eZQ8SEkAZULoAbiLnCyGSvvV6SC7IoBcS4Nw0wjcFbvJDcjiuTswzFDpiIQaHJ
  7.1558 +lQAjQUi1YRmUboC2uZJig8J4PaCnT5IaDcgsbm/CjinOwgx1KcUTMEhhTgV4g2B1fRk8Le8fv86v
  7.1559 +g7v545UHpZB9rKnp+gXsMhxLunIIpwVQxP/l9c/Hq9Xt1epm4R27bva6AJqN92G4YhbMG2i+LB+u
  7.1560 +grv71c3dY7B6WtzfLy9bePbp0taDTXSwJQJszUnnp0y57mvpPcrF7ZODyhswtd59+/jdgw+fwBNS
  7.1561 +xLSscksUPIDqwwNmCez3PpxGeyBYg6HE0YdcWBxcKczYzuVJi5Wu915vn5oWePCCoPUZBN5B7IgV
  7.1562 +MCi54ZDLG7TUZ0HweXkb3M5vFmSpFm/gthhBx0UrveoPpv9AJ9unIbQYdUoe21bKg2q48sPFGVwu
  7.1563 +H+afrxd1qvclaNlRFyh1EQ2sSccEuNAGWQwysfVpz1tPajUqbqJUnEcIJkWo6OXDaodK8ZiLdbmM
  7.1564 +L1wb+9H0D+pcyPSrX5u5kgWSygRYXCnJUi/KKcuU4cqsAyTKZBiissLc7NFwizvjxtieKBVCIdWz
  7.1565 +fzilzPaYyljZN0cGN1v7NnaIPNCGmVy3GKuJaQ6iVjE1Qfm+36hglErwmnAD8hu0dDy4uICBA8ZV
  7.1566 +pQr/q/+O0KFW2kjelu9Dgb9SDBsWV4F4x5CswgS0zBVlk5tDMP5bVtUGpslbm81Lu2sdKq7uNMGh
  7.1567 +MVQ4fy9xhogC1lS5guhISa0DlBWv0O8odT6/LP+4WZzDV6FzIkEqC0uolGZSZoMnlpxplmD2euaT
  7.1568 +O4hkTpPnbztDccey0bhjDaBIqaWQa0uwEtQEwtyU56i4fq54F9IE3ORR6mKriODM4XOYZwaVYLYz
  7.1569 +7SPbKkz4i7VkB6/Ot1upDE3znNqYKpM8raa0Bx8vfvntJ32UENsM4aI6gJL+jJwhxhh3jVIDOcpi
  7.1570 +m0r2hmEtS8XXXNBk71QCDXTBNhhPiHX2LtHkrVIlhoEshH/EZgdq53Eirqs5iFKMnkOmqZTtr3Xq
  7.1571 +djvPTWZT4S3NT5aVLgurMPUWI07BRVYqkQrmtCKohNY8qu9EdACoT6ki0a66XxVF4f9AQ3W38yO5
  7.1572 +mWmZmIIpnDFrbXakvKWeZhLwhvrbUH8fahhqD0YUcBDJjEBMQwiznE4y5QbHrbhHBOnUAYzb2tVN
  7.1573 +jJa65e+eE2Ya30E2GurxUP8ssA6e/wOnvo3V78d3vTcvMB3n7l3iX1JXWqk=
  7.1574 +""".decode("base64").decode("zlib")
  7.1575 +
  7.1576 +##file activate.csh
  7.1577 +ACTIVATE_CSH = """
  7.1578 +eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49
  7.1579 +XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp
  7.1580 +kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u
  7.1581 +pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx
  7.1582 +sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM
  7.1583 +yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu
  7.1584 +E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF
  7.1585 +lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7
  7.1586 +r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo=
  7.1587 +""".decode("base64").decode("zlib")
  7.1588 +
  7.1589 +##file activate.bat
  7.1590 +ACTIVATE_BAT = """
  7.1591 +eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
  7.1592 +qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
  7.1593 +sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
  7.1594 +ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
  7.1595 +""".decode("base64").decode("zlib")
  7.1596 +
  7.1597 +##file deactivate.bat
  7.1598 +DEACTIVATE_BAT = """
  7.1599 +eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
  7.1600 +FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
  7.1601 +i2dASrm4rFz9XLgAwJNbyQ==
  7.1602 +""".decode("base64").decode("zlib")
  7.1603 +
  7.1604 +##file distutils-init.py
  7.1605 +DISTUTILS_INIT = """
  7.1606 +eJytV92L4zYQf9dfMU0ottuse/TeFkKh3MvC0Ydy0IdlMVpbTtR1JCMpm+T++s5Y/pBs53oPZ1hQ
  7.1607 +pPnSb34zo5WnVhsH2jLpV/Y2Li/cKKkOFoYN3Za6ErAdFtKC0g44vEvjzrwR6h1Oujo3YgdWw0VA
  7.1608 +yRWcLUo6cBpqqSpwRwHWVY18ZRB9W3jq3HDlfoIvqK7NG2gF7a297VANvZ3O1sGrQI/eDe5yB0ZY
  7.1609 +WQkLUpHxhVX09NDe3FGr31BL1lJUD9f8ln+FShpROm1ujOFS8ZOAPUKRt9wd836Hjqw7O9nYgvYD
  7.1610 +iX+1VOlMPPXQ5EVRy0YURbaDZDSQZEzWo7rS5kSLNHaQwX4RRLrQGe1nj92Fh1zltEhHDDZfEO0g
  7.1611 +O6MraHn5xg8IpYOfLfC2FdxYShLC64EES4A0uuROYhq49Zs368RpMvTHJmOiscKHUXRXKIpcKiuM
  7.1612 +Sz/sYHa7TkxcRYkkEhN8HZaxKCJXFFJJh+baW5JluRG8SjM20JHEA9qWWtXywBjbbvF2rjzC61k2
  7.1613 +VSGuDibTUGlhVeLgTekLHPEP73wQrrscUsUGrPCGjkTCC1JXXyw8EJWP3FSUZY8IiSCCRp97dnfO
  7.1614 +RUUx5a0RtbxSzLX/3XBXYxIpyQka/fh74pGrjQ5QzUt9OnFV5dMV+otOG5gQjctxozNTNtzaSSiN
  7.1615 +JHqu0FeJmsqRN/KrKHRLGbaQWtHUgRB9FDfu5giN4eZWIDqWCv8vrcTjrNZgRXQPzy+RmGjQpLRI
  7.1616 +EKz0UqQLlR28ciusM8jn7PtcLPZy2zbSDeyyos0iO+ybBgPyRvSk/CEFm8IndQebz8iXTRbbjhDP
  7.1617 +5xh7iJfBrKd/Nenjj6Jvgp2B+W7AnP102BXH5IZWPV3tI2MUOvXowpdS12IIXhLLP0lKyeuZrpEv
  7.1618 +pFhPqHg3JFTd1cceVp0EsPgGU0wFO2u4iyYRoFYfEm9kG/RZcUUBm87t9mFtx9iCtC9kx4Rt4R8a
  7.1619 +OdgzSt40vtyFecAZZ8BfCOhCrC8djMGPFaz2Vlt5TSZCk053+37wbLDLRXfZ+F45NtdVpVWdudSC
  7.1620 +xgODI8EsiLoTl5aO0lhoigX7GHZDHAY4LxoMIu1gXPYPksmFquxF4uRKZhEnKzXu82HESb+LlNQz
  7.1621 +Fh/RvFJVuhK+Ee5slBdj30FcRGdJ5rhKxtkyKxWcGoV/WOCYKqkNDYJ5fNQVx3g400tpJBS2FSU+
  7.1622 +Tco9ss8nZ08dtscGQfSby87b73fOw+4UgrEMNnY6uMzYvSDxPVPpsij6+l0/ZPfuH0Iz010giY34
  7.1623 +HpL0ZLyLJB4ukaQRU+GwptO7yIZCQE33B0K9iCqO6X+AR4n7wAeH68DPkJzpTsD3x+/cj9LIVHC2
  7.1624 +An1wmv7CzWHoqR02vb0VL73siP+3nkX0YbQ0l9f6WDyOm24cj3rxO2MMip6kpcu6VCefn/789PR3
  7.1625 +0v0fg21sFIp70rj9PCi8YDRDXFucym/43qN+iENh1Jy/dIIIqF3OIkDvBMsdx+huWv8Kz73vl8g5
  7.1626 +WQ3JOGqwu3lb4dfKKbvLigXDQsb8B/xt39Q=
  7.1627 +""".decode("base64").decode("zlib")
  7.1628 +
  7.1629 +##file distutils.cfg
  7.1630 +DISTUTILS_CFG = """
  7.1631 +eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
  7.1632 +xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
  7.1633 +9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
  7.1634 +""".decode("base64").decode("zlib")
  7.1635 +
  7.1636 +##file activate_this.py
  7.1637 +ACTIVATE_THIS = """
  7.1638 +eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ
  7.1639 +VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a
  7.1640 +Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE
  7.1641 +qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX
  7.1642 +4lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7
  7.1643 +HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n
  7.1644 +xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96
  7.1645 +1Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI
  7.1646 +3vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU=
  7.1647 +""".decode("base64").decode("zlib")
  7.1648 +
  7.1649 +if __name__ == '__main__':
  7.1650 +    main()
  7.1651 +
  7.1652 +## TODO:
  7.1653 +## Copy python.exe.manifest
  7.1654 +## Monkeypatch distutils.sysconfig