virtualenv/setup/project-boot.py
changeset 99 a65807bd3d04
equal deleted inserted replaced
98:9c9d78982380 99:a65807bd3d04
       
     1 #!/usr/bin/env python2.6
       
     2 ## WARNING: This file is generated
       
     3 #!/usr/bin/env python
       
     4 """Create a "virtual" Python installation
       
     5 """
       
     6 
       
     7 virtualenv_version = "1.4.9"
       
     8 
       
     9 import sys
       
    10 import os
       
    11 import optparse
       
    12 import re
       
    13 import shutil
       
    14 import logging
       
    15 import tempfile
       
    16 import distutils.sysconfig
       
    17 try:
       
    18     import subprocess
       
    19 except ImportError, e:
       
    20     if sys.version_info <= (2, 3):
       
    21         print 'ERROR: %s' % e
       
    22         print 'ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.'
       
    23         print 'If you copy subprocess.py from a newer version of Python this script will probably work'
       
    24         sys.exit(101)
       
    25     else:
       
    26         raise
       
    27 try:
       
    28     set
       
    29 except NameError:
       
    30     from sets import Set as set
       
    31 
       
    32 join = os.path.join
       
    33 py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
       
    34 is_jython = sys.platform.startswith('java')
       
    35 expected_exe = is_jython and 'jython' or 'python'
       
    36 
       
    37 REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
       
    38                     'fnmatch', 'locale', 'encodings', 'codecs',
       
    39                     'stat', 'UserDict', 'readline', 'copy_reg', 'types',
       
    40                     're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
       
    41                     'lib-dynload', 'config', 'zlib']
       
    42 
       
    43 if sys.version_info[:2] >= (2, 6):
       
    44     REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
       
    45 if sys.version_info[:2] <= (2, 3):
       
    46     REQUIRED_MODULES.extend(['sets', '__future__'])
       
    47 
       
    48 class Logger(object):
       
    49 
       
    50     """
       
    51     Logging object for use in command-line script.  Allows ranges of
       
    52     levels, to avoid some redundancy of displayed information.
       
    53     """
       
    54 
       
    55     DEBUG = logging.DEBUG
       
    56     INFO = logging.INFO
       
    57     NOTIFY = (logging.INFO+logging.WARN)/2
       
    58     WARN = WARNING = logging.WARN
       
    59     ERROR = logging.ERROR
       
    60     FATAL = logging.FATAL
       
    61 
       
    62     LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
       
    63 
       
    64     def __init__(self, consumers):
       
    65         self.consumers = consumers
       
    66         self.indent = 0
       
    67         self.in_progress = None
       
    68         self.in_progress_hanging = False
       
    69 
       
    70     def debug(self, msg, *args, **kw):
       
    71         self.log(self.DEBUG, msg, *args, **kw)
       
    72     def info(self, msg, *args, **kw):
       
    73         self.log(self.INFO, msg, *args, **kw)
       
    74     def notify(self, msg, *args, **kw):
       
    75         self.log(self.NOTIFY, msg, *args, **kw)
       
    76     def warn(self, msg, *args, **kw):
       
    77         self.log(self.WARN, msg, *args, **kw)
       
    78     def error(self, msg, *args, **kw):
       
    79         self.log(self.WARN, msg, *args, **kw)
       
    80     def fatal(self, msg, *args, **kw):
       
    81         self.log(self.FATAL, msg, *args, **kw)
       
    82     def log(self, level, msg, *args, **kw):
       
    83         if args:
       
    84             if kw:
       
    85                 raise TypeError(
       
    86                     "You may give positional or keyword arguments, not both")
       
    87         args = args or kw
       
    88         rendered = None
       
    89         for consumer_level, consumer in self.consumers:
       
    90             if self.level_matches(level, consumer_level):
       
    91                 if (self.in_progress_hanging
       
    92                     and consumer in (sys.stdout, sys.stderr)):
       
    93                     self.in_progress_hanging = False
       
    94                     sys.stdout.write('\n')
       
    95                     sys.stdout.flush()
       
    96                 if rendered is None:
       
    97                     if args:
       
    98                         rendered = msg % args
       
    99                     else:
       
   100                         rendered = msg
       
   101                     rendered = ' '*self.indent + rendered
       
   102                 if hasattr(consumer, 'write'):
       
   103                     consumer.write(rendered+'\n')
       
   104                 else:
       
   105                     consumer(rendered)
       
   106 
       
   107     def start_progress(self, msg):
       
   108         assert not self.in_progress, (
       
   109             "Tried to start_progress(%r) while in_progress %r"
       
   110             % (msg, self.in_progress))
       
   111         if self.level_matches(self.NOTIFY, self._stdout_level()):
       
   112             sys.stdout.write(msg)
       
   113             sys.stdout.flush()
       
   114             self.in_progress_hanging = True
       
   115         else:
       
   116             self.in_progress_hanging = False
       
   117         self.in_progress = msg
       
   118 
       
   119     def end_progress(self, msg='done.'):
       
   120         assert self.in_progress, (
       
   121             "Tried to end_progress without start_progress")
       
   122         if self.stdout_level_matches(self.NOTIFY):
       
   123             if not self.in_progress_hanging:
       
   124                 # Some message has been printed out since start_progress
       
   125                 sys.stdout.write('...' + self.in_progress + msg + '\n')
       
   126                 sys.stdout.flush()
       
   127             else:
       
   128                 sys.stdout.write(msg + '\n')
       
   129                 sys.stdout.flush()
       
   130         self.in_progress = None
       
   131         self.in_progress_hanging = False
       
   132 
       
   133     def show_progress(self):
       
   134         """If we are in a progress scope, and no log messages have been
       
   135         shown, write out another '.'"""
       
   136         if self.in_progress_hanging:
       
   137             sys.stdout.write('.')
       
   138             sys.stdout.flush()
       
   139 
       
   140     def stdout_level_matches(self, level):
       
   141         """Returns true if a message at this level will go to stdout"""
       
   142         return self.level_matches(level, self._stdout_level())
       
   143 
       
   144     def _stdout_level(self):
       
   145         """Returns the level that stdout runs at"""
       
   146         for level, consumer in self.consumers:
       
   147             if consumer is sys.stdout:
       
   148                 return level
       
   149         return self.FATAL
       
   150 
       
   151     def level_matches(self, level, consumer_level):
       
   152         """
       
   153         >>> l = Logger()
       
   154         >>> l.level_matches(3, 4)
       
   155         False
       
   156         >>> l.level_matches(3, 2)
       
   157         True
       
   158         >>> l.level_matches(slice(None, 3), 3)
       
   159         False
       
   160         >>> l.level_matches(slice(None, 3), 2)
       
   161         True
       
   162         >>> l.level_matches(slice(1, 3), 1)
       
   163         True
       
   164         >>> l.level_matches(slice(2, 3), 1)
       
   165         False
       
   166         """
       
   167         if isinstance(level, slice):
       
   168             start, stop = level.start, level.stop
       
   169             if start is not None and start > consumer_level:
       
   170                 return False
       
   171             if stop is not None or stop <= consumer_level:
       
   172                 return False
       
   173             return True
       
   174         else:
       
   175             return level >= consumer_level
       
   176 
       
   177     #@classmethod
       
   178     def level_for_integer(cls, level):
       
   179         levels = cls.LEVELS
       
   180         if level < 0:
       
   181             return levels[0]
       
   182         if level >= len(levels):
       
   183             return levels[-1]
       
   184         return levels[level]
       
   185 
       
   186     level_for_integer = classmethod(level_for_integer)
       
   187 
       
   188 def mkdir(path):
       
   189     if not os.path.exists(path):
       
   190         logger.info('Creating %s', path)
       
   191         os.makedirs(path)
       
   192     else:
       
   193         logger.info('Directory %s already exists', path)
       
   194 
       
   195 def copyfile(src, dest, symlink=True):
       
   196     if not os.path.exists(src):
       
   197         # Some bad symlink in the src
       
   198         logger.warn('Cannot find file %s (bad symlink)', src)
       
   199         return
       
   200     if os.path.exists(dest):
       
   201         logger.debug('File %s already exists', dest)
       
   202         return
       
   203     if not os.path.exists(os.path.dirname(dest)):
       
   204         logger.info('Creating parent directories for %s' % os.path.dirname(dest))
       
   205         os.makedirs(os.path.dirname(dest))
       
   206     if symlink and hasattr(os, 'symlink'):
       
   207         logger.info('Symlinking %s', dest)
       
   208         os.symlink(os.path.abspath(src), dest)
       
   209     else:
       
   210         logger.info('Copying to %s', dest)
       
   211         if os.path.isdir(src):
       
   212             shutil.copytree(src, dest, True)
       
   213         else:
       
   214             shutil.copy2(src, dest)
       
   215 
       
   216 def writefile(dest, content, overwrite=True):
       
   217     if not os.path.exists(dest):
       
   218         logger.info('Writing %s', dest)
       
   219         f = open(dest, 'wb')
       
   220         f.write(content)
       
   221         f.close()
       
   222         return
       
   223     else:
       
   224         f = open(dest, 'rb')
       
   225         c = f.read()
       
   226         f.close()
       
   227         if c != content:
       
   228             if not overwrite:
       
   229                 logger.notify('File %s exists with different content; not overwriting', dest)
       
   230                 return
       
   231             logger.notify('Overwriting %s with new content', dest)
       
   232             f = open(dest, 'wb')
       
   233             f.write(content)
       
   234             f.close()
       
   235         else:
       
   236             logger.info('Content %s already in place', dest)
       
   237 
       
   238 def rmtree(dir):
       
   239     if os.path.exists(dir):
       
   240         logger.notify('Deleting tree %s', dir)
       
   241         shutil.rmtree(dir)
       
   242     else:
       
   243         logger.info('Do not need to delete %s; already gone', dir)
       
   244 
       
   245 def make_exe(fn):
       
   246     if hasattr(os, 'chmod'):
       
   247         oldmode = os.stat(fn).st_mode & 07777
       
   248         newmode = (oldmode | 0555) & 07777
       
   249         os.chmod(fn, newmode)
       
   250         logger.info('Changed mode of %s to %s', fn, oct(newmode))
       
   251 
       
   252 def _find_file(filename, dirs):
       
   253     for dir in dirs:
       
   254         if os.path.exists(join(dir, filename)):
       
   255             return join(dir, filename)
       
   256     return filename
       
   257 
       
   258 def _install_req(py_executable, unzip=False, distribute=False):
       
   259     if not distribute:
       
   260         setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
       
   261         project_name = 'setuptools'
       
   262         bootstrap_script = EZ_SETUP_PY
       
   263         source = None
       
   264     else:
       
   265         setup_fn = None
       
   266         source = 'distribute-0.6.8.tar.gz'
       
   267         project_name = 'distribute'
       
   268         bootstrap_script = DISTRIBUTE_SETUP_PY
       
   269         try:
       
   270             # check if the global Python has distribute installed or plain
       
   271             # setuptools
       
   272             import pkg_resources
       
   273             if not hasattr(pkg_resources, '_distribute'):
       
   274                 location = os.path.dirname(pkg_resources.__file__)
       
   275                 logger.notify("A globally installed setuptools was found (in %s)" % location)
       
   276                 logger.notify("Use the --no-site-packages option to use distribute in "
       
   277                               "the virtualenv.")
       
   278         except ImportError:
       
   279             pass
       
   280 
       
   281     search_dirs = file_search_dirs()
       
   282 
       
   283     if setup_fn is not None:
       
   284         setup_fn = _find_file(setup_fn, search_dirs)
       
   285 
       
   286     if source is not None:
       
   287         source = _find_file(source, search_dirs)
       
   288 
       
   289     if is_jython and os._name == 'nt':
       
   290         # Jython's .bat sys.executable can't handle a command line
       
   291         # argument with newlines
       
   292         fd, ez_setup = tempfile.mkstemp('.py')
       
   293         os.write(fd, bootstrap_script)
       
   294         os.close(fd)
       
   295         cmd = [py_executable, ez_setup]
       
   296     else:
       
   297         cmd = [py_executable, '-c', bootstrap_script]
       
   298     if unzip:
       
   299         cmd.append('--always-unzip')
       
   300     env = {}
       
   301     if logger.stdout_level_matches(logger.DEBUG):
       
   302         cmd.append('-v')
       
   303 
       
   304     old_chdir = os.getcwd()
       
   305     if setup_fn is not None and os.path.exists(setup_fn):
       
   306         logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
       
   307         cmd.append(setup_fn)
       
   308         if os.environ.get('PYTHONPATH'):
       
   309             env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
       
   310         else:
       
   311             env['PYTHONPATH'] = setup_fn
       
   312     else:
       
   313         # the source is found, let's chdir
       
   314         if source is not None and os.path.exists(source):
       
   315             os.chdir(os.path.dirname(source))
       
   316         else:
       
   317             logger.info('No %s egg found; downloading' % project_name)
       
   318         cmd.extend(['--always-copy', '-U', project_name])
       
   319     logger.start_progress('Installing %s...' % project_name)
       
   320     logger.indent += 2
       
   321     cwd = None
       
   322     if project_name == 'distribute':
       
   323         env['DONT_PATCH_SETUPTOOLS'] = 'true'
       
   324 
       
   325     def _filter_ez_setup(line):
       
   326         return filter_ez_setup(line, project_name)
       
   327 
       
   328     if not os.access(os.getcwd(), os.W_OK):
       
   329         cwd = tempfile.mkdtemp()
       
   330         if source is not None and os.path.exists(source):
       
   331             # the current working dir is hostile, let's copy the
       
   332             # tarball to a temp dir
       
   333             target = os.path.join(cwd, os.path.split(source)[-1])
       
   334             shutil.copy(source, target)
       
   335     try:
       
   336         call_subprocess(cmd, show_stdout=False,
       
   337                         filter_stdout=_filter_ez_setup,
       
   338                         extra_env=env,
       
   339                         cwd=cwd)
       
   340     finally:
       
   341         logger.indent -= 2
       
   342         logger.end_progress()
       
   343         if os.getcwd() != old_chdir:
       
   344             os.chdir(old_chdir)
       
   345         if is_jython and os._name == 'nt':
       
   346             os.remove(ez_setup)
       
   347 
       
   348 def file_search_dirs():
       
   349     here = os.path.dirname(os.path.abspath(__file__))
       
   350     dirs = ['.', here,
       
   351             join(here, 'virtualenv_support')]
       
   352     if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
       
   353         # Probably some boot script; just in case virtualenv is installed...
       
   354         try:
       
   355             import virtualenv
       
   356         except ImportError:
       
   357             pass
       
   358         else:
       
   359             dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
       
   360     return [d for d in dirs if os.path.isdir(d)]
       
   361 
       
   362 def install_setuptools(py_executable, unzip=False):
       
   363     _install_req(py_executable, unzip)
       
   364 
       
   365 def install_distribute(py_executable, unzip=False):
       
   366     _install_req(py_executable, unzip, distribute=True)
       
   367 
       
   368 _pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
       
   369 def install_pip(py_executable):
       
   370     filenames = []
       
   371     for dir in file_search_dirs():
       
   372         filenames.extend([join(dir, fn) for fn in os.listdir(dir)
       
   373                           if _pip_re.search(fn)])
       
   374     filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
       
   375     filenames.sort()
       
   376     filenames = [filename for basename, i, filename in filenames]
       
   377     if not filenames:
       
   378         filename = 'pip'
       
   379     else:
       
   380         filename = filenames[-1]
       
   381     easy_install_script = 'easy_install'
       
   382     if sys.platform == 'win32':
       
   383         easy_install_script = 'easy_install-script.py'
       
   384     cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename]
       
   385     if filename == 'pip':
       
   386         logger.info('Installing pip from network...')
       
   387     else:
       
   388         logger.info('Installing %s' % os.path.basename(filename))
       
   389     logger.indent += 2
       
   390     def _filter_setup(line):
       
   391         return filter_ez_setup(line, 'pip')
       
   392     try:
       
   393         call_subprocess(cmd, show_stdout=False,
       
   394                         filter_stdout=_filter_setup)
       
   395     finally:
       
   396         logger.indent -= 2
       
   397 
       
   398 def filter_ez_setup(line, project_name='setuptools'):
       
   399     if not line.strip():
       
   400         return Logger.DEBUG
       
   401     if project_name == 'distribute':
       
   402         for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
       
   403                        'Scanning', 'Setuptools', 'Egg', 'Already',
       
   404                        'running', 'writing', 'reading', 'installing',
       
   405                        'creating', 'copying', 'byte-compiling', 'removing',
       
   406                        'Processing'):
       
   407             if line.startswith(prefix):
       
   408                 return Logger.DEBUG
       
   409         return Logger.DEBUG
       
   410     for prefix in ['Reading ', 'Best match', 'Processing setuptools',
       
   411                    'Copying setuptools', 'Adding setuptools',
       
   412                    'Installing ', 'Installed ']:
       
   413         if line.startswith(prefix):
       
   414             return Logger.DEBUG
       
   415     return Logger.INFO
       
   416 
       
   417 def main():
       
   418     parser = optparse.OptionParser(
       
   419         version=virtualenv_version,
       
   420         usage="%prog [OPTIONS] DEST_DIR")
       
   421 
       
   422     parser.add_option(
       
   423         '-v', '--verbose',
       
   424         action='count',
       
   425         dest='verbose',
       
   426         default=0,
       
   427         help="Increase verbosity")
       
   428 
       
   429     parser.add_option(
       
   430         '-q', '--quiet',
       
   431         action='count',
       
   432         dest='quiet',
       
   433         default=0,
       
   434         help='Decrease verbosity')
       
   435 
       
   436     parser.add_option(
       
   437         '-p', '--python',
       
   438         dest='python',
       
   439         metavar='PYTHON_EXE',
       
   440         help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
       
   441         'interpreter to create the new environment.  The default is the interpreter that '
       
   442         'virtualenv was installed with (%s)' % sys.executable)
       
   443 
       
   444     parser.add_option(
       
   445         '--clear',
       
   446         dest='clear',
       
   447         action='store_true',
       
   448         help="Clear out the non-root install and start from scratch")
       
   449 
       
   450     parser.add_option(
       
   451         '--no-site-packages',
       
   452         dest='no_site_packages',
       
   453         action='store_true',
       
   454         help="Don't give access to the global site-packages dir to the "
       
   455              "virtual environment")
       
   456 
       
   457     parser.add_option(
       
   458         '--unzip-setuptools',
       
   459         dest='unzip_setuptools',
       
   460         action='store_true',
       
   461         help="Unzip Setuptools or Distribute when installing it")
       
   462 
       
   463     parser.add_option(
       
   464         '--relocatable',
       
   465         dest='relocatable',
       
   466         action='store_true',
       
   467         help='Make an EXISTING virtualenv environment relocatable.  '
       
   468         'This fixes up scripts and makes all .pth files relative')
       
   469 
       
   470     parser.add_option(
       
   471         '--distribute',
       
   472         dest='use_distribute',
       
   473         action='store_true',
       
   474         help='Use Distribute instead of Setuptools. Set environ variable '
       
   475         'VIRTUALENV_USE_DISTRIBUTE to make it the default ')
       
   476 
       
   477     parser.add_option(
       
   478         '--prompt=',
       
   479         dest='prompt',
       
   480         help='Provides an alternative prompt prefix for this environment')
       
   481 
       
   482     if 'extend_parser' in globals():
       
   483         extend_parser(parser)
       
   484 
       
   485     options, args = parser.parse_args()
       
   486 
       
   487     global logger
       
   488 
       
   489     if 'adjust_options' in globals():
       
   490         adjust_options(options, args)
       
   491 
       
   492     verbosity = options.verbose - options.quiet
       
   493     logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
       
   494 
       
   495     if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
       
   496         env = os.environ.copy()
       
   497         interpreter = resolve_interpreter(options.python)
       
   498         if interpreter == sys.executable:
       
   499             logger.warn('Already using interpreter %s' % interpreter)
       
   500         else:
       
   501             logger.notify('Running virtualenv with interpreter %s' % interpreter)
       
   502             env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
       
   503             file = __file__
       
   504             if file.endswith('.pyc'):
       
   505                 file = file[:-1]
       
   506             popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
       
   507             raise SystemExit(popen.wait())
       
   508 
       
   509     if not args:
       
   510         print 'You must provide a DEST_DIR'
       
   511         parser.print_help()
       
   512         sys.exit(2)
       
   513     if len(args) > 1:
       
   514         print 'There must be only one argument: DEST_DIR (you gave %s)' % (
       
   515             ' '.join(args))
       
   516         parser.print_help()
       
   517         sys.exit(2)
       
   518 
       
   519     home_dir = args[0]
       
   520 
       
   521     if os.environ.get('WORKING_ENV'):
       
   522         logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
       
   523         logger.fatal('Please deactivate your workingenv, then re-run this script')
       
   524         sys.exit(3)
       
   525 
       
   526     if 'PYTHONHOME' in os.environ:
       
   527         logger.warn('PYTHONHOME is set.  You *must* activate the virtualenv before using it')
       
   528         del os.environ['PYTHONHOME']
       
   529 
       
   530     if options.relocatable:
       
   531         make_environment_relocatable(home_dir)
       
   532         return
       
   533 
       
   534     create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
       
   535                        unzip_setuptools=options.unzip_setuptools,
       
   536                        use_distribute=options.use_distribute,
       
   537                        prompt=options.prompt)
       
   538     if 'after_install' in globals():
       
   539         after_install(options, home_dir)
       
   540 
       
   541 def call_subprocess(cmd, show_stdout=True,
       
   542                     filter_stdout=None, cwd=None,
       
   543                     raise_on_returncode=True, extra_env=None):
       
   544     cmd_parts = []
       
   545     for part in cmd:
       
   546         if len(part) > 40:
       
   547             part = part[:30]+"..."+part[-5:]
       
   548         if ' ' in part or '\n' in part or '"' in part or "'" in part:
       
   549             part = '"%s"' % part.replace('"', '\\"')
       
   550         cmd_parts.append(part)
       
   551     cmd_desc = ' '.join(cmd_parts)
       
   552     if show_stdout:
       
   553         stdout = None
       
   554     else:
       
   555         stdout = subprocess.PIPE
       
   556     logger.debug("Running command %s" % cmd_desc)
       
   557     if extra_env:
       
   558         env = os.environ.copy()
       
   559         env.update(extra_env)
       
   560     else:
       
   561         env = None
       
   562     try:
       
   563         proc = subprocess.Popen(
       
   564             cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
       
   565             cwd=cwd, env=env)
       
   566     except Exception, e:
       
   567         logger.fatal(
       
   568             "Error %s while executing command %s" % (e, cmd_desc))
       
   569         raise
       
   570     all_output = []
       
   571     if stdout is not None:
       
   572         stdout = proc.stdout
       
   573         while 1:
       
   574             line = stdout.readline()
       
   575             if not line:
       
   576                 break
       
   577             line = line.rstrip()
       
   578             all_output.append(line)
       
   579             if filter_stdout:
       
   580                 level = filter_stdout(line)
       
   581                 if isinstance(level, tuple):
       
   582                     level, line = level
       
   583                 logger.log(level, line)
       
   584                 if not logger.stdout_level_matches(level):
       
   585                     logger.show_progress()
       
   586             else:
       
   587                 logger.info(line)
       
   588     else:
       
   589         proc.communicate()
       
   590     proc.wait()
       
   591     if proc.returncode:
       
   592         if raise_on_returncode:
       
   593             if all_output:
       
   594                 logger.notify('Complete output from command %s:' % cmd_desc)
       
   595                 logger.notify('\n'.join(all_output) + '\n----------------------------------------')
       
   596             raise OSError(
       
   597                 "Command %s failed with error code %s"
       
   598                 % (cmd_desc, proc.returncode))
       
   599         else:
       
   600             logger.warn(
       
   601                 "Command %s had error code %s"
       
   602                 % (cmd_desc, proc.returncode))
       
   603 
       
   604 
       
   605 def create_environment(home_dir, site_packages=True, clear=False,
       
   606                        unzip_setuptools=False, use_distribute=False,
       
   607                        prompt=None):
       
   608     """
       
   609     Creates a new environment in ``home_dir``.
       
   610 
       
   611     If ``site_packages`` is true (the default) then the global
       
   612     ``site-packages/`` directory will be on the path.
       
   613 
       
   614     If ``clear`` is true (default False) then the environment will
       
   615     first be cleared.
       
   616     """
       
   617     home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
       
   618 
       
   619     py_executable = os.path.abspath(install_python(
       
   620         home_dir, lib_dir, inc_dir, bin_dir,
       
   621         site_packages=site_packages, clear=clear))
       
   622 
       
   623     install_distutils(lib_dir, home_dir)
       
   624 
       
   625     if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
       
   626         install_distribute(py_executable, unzip=unzip_setuptools)
       
   627     else:
       
   628         install_setuptools(py_executable, unzip=unzip_setuptools)
       
   629 
       
   630     install_pip(py_executable)
       
   631 
       
   632     install_activate(home_dir, bin_dir, prompt)
       
   633 
       
   634 def path_locations(home_dir):
       
   635     """Return the path locations for the environment (where libraries are,
       
   636     where scripts go, etc)"""
       
   637     # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
       
   638     # prefix arg is broken: http://bugs.python.org/issue3386
       
   639     if sys.platform == 'win32':
       
   640         # Windows has lots of problems with executables with spaces in
       
   641         # the name; this function will remove them (using the ~1
       
   642         # format):
       
   643         mkdir(home_dir)
       
   644         if ' ' in home_dir:
       
   645             try:
       
   646                 import win32api
       
   647             except ImportError:
       
   648                 print 'Error: the path "%s" has a space in it' % home_dir
       
   649                 print 'To handle these kinds of paths, the win32api module must be installed:'
       
   650                 print '  http://sourceforge.net/projects/pywin32/'
       
   651                 sys.exit(3)
       
   652             home_dir = win32api.GetShortPathName(home_dir)
       
   653         lib_dir = join(home_dir, 'Lib')
       
   654         inc_dir = join(home_dir, 'Include')
       
   655         bin_dir = join(home_dir, 'Scripts')
       
   656     elif is_jython:
       
   657         lib_dir = join(home_dir, 'Lib')
       
   658         inc_dir = join(home_dir, 'Include')
       
   659         bin_dir = join(home_dir, 'bin')
       
   660     else:
       
   661         lib_dir = join(home_dir, 'lib', py_version)
       
   662         inc_dir = join(home_dir, 'include', py_version)
       
   663         bin_dir = join(home_dir, 'bin')
       
   664     return home_dir, lib_dir, inc_dir, bin_dir
       
   665 
       
   666 def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
       
   667     """Install just the base environment, no distutils patches etc"""
       
   668     if sys.executable.startswith(bin_dir):
       
   669         print 'Please use the *system* python to run this script'
       
   670         return
       
   671 
       
   672     if clear:
       
   673         rmtree(lib_dir)
       
   674         ## FIXME: why not delete it?
       
   675         ## Maybe it should delete everything with #!/path/to/venv/python in it
       
   676         logger.notify('Not deleting %s', bin_dir)
       
   677 
       
   678     if hasattr(sys, 'real_prefix'):
       
   679         logger.notify('Using real prefix %r' % sys.real_prefix)
       
   680         prefix = sys.real_prefix
       
   681     else:
       
   682         prefix = sys.prefix
       
   683     mkdir(lib_dir)
       
   684     fix_lib64(lib_dir)
       
   685     stdlib_dirs = [os.path.dirname(os.__file__)]
       
   686     if sys.platform == 'win32':
       
   687         stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
       
   688     elif sys.platform == 'darwin':
       
   689         stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
       
   690     for stdlib_dir in stdlib_dirs:
       
   691         if not os.path.isdir(stdlib_dir):
       
   692             continue
       
   693         if hasattr(os, 'symlink'):
       
   694             logger.info('Symlinking Python bootstrap modules')
       
   695         else:
       
   696             logger.info('Copying Python bootstrap modules')
       
   697         logger.indent += 2
       
   698         try:
       
   699             for fn in os.listdir(stdlib_dir):
       
   700                 if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_MODULES:
       
   701                     copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
       
   702         finally:
       
   703             logger.indent -= 2
       
   704     mkdir(join(lib_dir, 'site-packages'))
       
   705     writefile(join(lib_dir, 'site.py'), SITE_PY)
       
   706     writefile(join(lib_dir, 'orig-prefix.txt'), prefix)
       
   707     site_packages_filename = join(lib_dir, 'no-global-site-packages.txt')
       
   708     if not site_packages:
       
   709         writefile(site_packages_filename, '')
       
   710     else:
       
   711         if os.path.exists(site_packages_filename):
       
   712             logger.info('Deleting %s' % site_packages_filename)
       
   713             os.unlink(site_packages_filename)
       
   714 
       
   715     stdinc_dir = join(prefix, 'include', py_version)
       
   716     if os.path.exists(stdinc_dir):
       
   717         copyfile(stdinc_dir, inc_dir)
       
   718     else:
       
   719         logger.debug('No include dir %s' % stdinc_dir)
       
   720 
       
   721     if sys.exec_prefix != prefix:
       
   722         if sys.platform == 'win32':
       
   723             exec_dir = join(sys.exec_prefix, 'lib')
       
   724         elif is_jython:
       
   725             exec_dir = join(sys.exec_prefix, 'Lib')
       
   726         else:
       
   727             exec_dir = join(sys.exec_prefix, 'lib', py_version)
       
   728         for fn in os.listdir(exec_dir):
       
   729             copyfile(join(exec_dir, fn), join(lib_dir, fn))
       
   730 
       
   731     if is_jython:
       
   732         # Jython has either jython-dev.jar and javalib/ dir, or just
       
   733         # jython.jar
       
   734         for name in 'jython-dev.jar', 'javalib', 'jython.jar':
       
   735             src = join(prefix, name)
       
   736             if os.path.exists(src):
       
   737                 copyfile(src, join(home_dir, name))
       
   738         # XXX: registry should always exist after Jython 2.5rc1
       
   739         src = join(prefix, 'registry')
       
   740         if os.path.exists(src):
       
   741             copyfile(src, join(home_dir, 'registry'), symlink=False)
       
   742         copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
       
   743                  symlink=False)
       
   744 
       
   745     mkdir(bin_dir)
       
   746     py_executable = join(bin_dir, os.path.basename(sys.executable))
       
   747     if 'Python.framework' in prefix:
       
   748         if re.search(r'/Python(?:-32|-64)*$', py_executable):
       
   749             # The name of the python executable is not quite what
       
   750             # we want, rename it.
       
   751             py_executable = os.path.join(
       
   752                     os.path.dirname(py_executable), 'python')
       
   753 
       
   754     logger.notify('New %s executable in %s', expected_exe, py_executable)
       
   755     if sys.executable != py_executable:
       
   756         ## FIXME: could I just hard link?
       
   757         executable = sys.executable
       
   758         if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
       
   759             # Cygwin misreports sys.executable sometimes
       
   760             executable += '.exe'
       
   761             py_executable += '.exe'
       
   762             logger.info('Executable actually exists in %s' % executable)
       
   763         shutil.copyfile(executable, py_executable)
       
   764         make_exe(py_executable)
       
   765         if sys.platform == 'win32' or sys.platform == 'cygwin':
       
   766             pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
       
   767             if os.path.exists(pythonw):
       
   768                 logger.info('Also created pythonw.exe')
       
   769                 shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
       
   770 
       
   771     if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
       
   772         secondary_exe = os.path.join(os.path.dirname(py_executable),
       
   773                                      expected_exe)
       
   774         py_executable_ext = os.path.splitext(py_executable)[1]
       
   775         if py_executable_ext == '.exe':
       
   776             # python2.4 gives an extension of '.4' :P
       
   777             secondary_exe += py_executable_ext
       
   778         if os.path.exists(secondary_exe):
       
   779             logger.warn('Not overwriting existing %s script %s (you must use %s)'
       
   780                         % (expected_exe, secondary_exe, py_executable))
       
   781         else:
       
   782             logger.notify('Also creating executable in %s' % secondary_exe)
       
   783             shutil.copyfile(sys.executable, secondary_exe)
       
   784             make_exe(secondary_exe)
       
   785 
       
   786     if 'Python.framework' in prefix:
       
   787         logger.debug('MacOSX Python framework detected')
       
   788 
       
   789         # Make sure we use the the embedded interpreter inside
       
   790         # the framework, even if sys.executable points to
       
   791         # the stub executable in ${sys.prefix}/bin
       
   792         # See http://groups.google.com/group/python-virtualenv/
       
   793         #                              browse_thread/thread/17cab2f85da75951
       
   794         original_python = os.path.join(
       
   795             prefix, 'Resources/Python.app/Contents/MacOS/Python')
       
   796         shutil.copy(original_python, py_executable)
       
   797 
       
   798         # Copy the framework's dylib into the virtual
       
   799         # environment
       
   800         virtual_lib = os.path.join(home_dir, '.Python')
       
   801 
       
   802         if os.path.exists(virtual_lib):
       
   803             os.unlink(virtual_lib)
       
   804         copyfile(
       
   805             os.path.join(prefix, 'Python'),
       
   806             virtual_lib)
       
   807 
       
   808         # And then change the install_name of the copied python executable
       
   809         try:
       
   810             call_subprocess(
       
   811                 ["install_name_tool", "-change",
       
   812                  os.path.join(prefix, 'Python'),
       
   813                  '@executable_path/../.Python',
       
   814                  py_executable])
       
   815         except:
       
   816             logger.fatal(
       
   817                 "Could not call install_name_tool -- you must have Apple's development tools installed")
       
   818             raise
       
   819 
       
   820         # Some tools depend on pythonX.Y being present
       
   821         py_executable_version = '%s.%s' % (
       
   822             sys.version_info[0], sys.version_info[1])
       
   823         if not py_executable.endswith(py_executable_version):
       
   824             # symlinking pythonX.Y > python
       
   825             pth = py_executable + '%s.%s' % (
       
   826                     sys.version_info[0], sys.version_info[1])
       
   827             if os.path.exists(pth):
       
   828                 os.unlink(pth)
       
   829             os.symlink('python', pth)
       
   830         else:
       
   831             # reverse symlinking python -> pythonX.Y (with --python)
       
   832             pth = join(bin_dir, 'python')
       
   833             if os.path.exists(pth):
       
   834                 os.unlink(pth)
       
   835             os.symlink(os.path.basename(py_executable), pth)
       
   836 
       
   837     if sys.platform == 'win32' and ' ' in py_executable:
       
   838         # There's a bug with subprocess on Windows when using a first
       
   839         # argument that has a space in it.  Instead we have to quote
       
   840         # the value:
       
   841         py_executable = '"%s"' % py_executable
       
   842     cmd = [py_executable, '-c', 'import sys; print sys.prefix']
       
   843     logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
       
   844     proc = subprocess.Popen(cmd,
       
   845                             stdout=subprocess.PIPE)
       
   846     proc_stdout, proc_stderr = proc.communicate()
       
   847     proc_stdout = os.path.normcase(os.path.abspath(proc_stdout.strip()))
       
   848     if proc_stdout != os.path.normcase(os.path.abspath(home_dir)):
       
   849         logger.fatal(
       
   850             'ERROR: The executable %s is not functioning' % py_executable)
       
   851         logger.fatal(
       
   852             'ERROR: It thinks sys.prefix is %r (should be %r)'
       
   853             % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
       
   854         logger.fatal(
       
   855             'ERROR: virtualenv is not compatible with this system or executable')
       
   856         if sys.platform == 'win32':
       
   857             logger.fatal(
       
   858                 '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)')
       
   859         sys.exit(100)
       
   860     else:
       
   861         logger.info('Got sys.prefix result: %r' % proc_stdout)
       
   862 
       
   863     pydistutils = os.path.expanduser('~/.pydistutils.cfg')
       
   864     if os.path.exists(pydistutils):
       
   865         logger.notify('Please make sure you remove any previous custom paths from '
       
   866                       'your %s file.' % pydistutils)
       
   867     ## FIXME: really this should be calculated earlier
       
   868     return py_executable
       
   869 
       
   870 def install_activate(home_dir, bin_dir, prompt=None):
       
   871     if sys.platform == 'win32' or is_jython and os._name == 'nt':
       
   872         files = {'activate.bat': ACTIVATE_BAT,
       
   873                  'deactivate.bat': DEACTIVATE_BAT}
       
   874         if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
       
   875             files['activate'] = ACTIVATE_SH
       
   876     else:
       
   877         files = {'activate': ACTIVATE_SH}
       
   878     files['activate_this.py'] = ACTIVATE_THIS
       
   879     vname = os.path.basename(os.path.abspath(home_dir))
       
   880     for name, content in files.items():
       
   881         content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
       
   882         content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
       
   883         content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir))
       
   884         content = content.replace('__VIRTUAL_NAME__', vname)
       
   885         content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
       
   886         writefile(os.path.join(bin_dir, name), content)
       
   887 
       
   888 def install_distutils(lib_dir, home_dir):
       
   889     distutils_path = os.path.join(lib_dir, 'distutils')
       
   890     mkdir(distutils_path)
       
   891     ## FIXME: maybe this prefix setting should only be put in place if
       
   892     ## there's a local distutils.cfg with a prefix setting?
       
   893     home_dir = os.path.abspath(home_dir)
       
   894     ## FIXME: this is breaking things, removing for now:
       
   895     #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
       
   896     writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
       
   897     writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
       
   898 
       
   899 def fix_lib64(lib_dir):
       
   900     """
       
   901     Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
       
   902     instead of lib/pythonX.Y.  If this is such a platform we'll just create a
       
   903     symlink so lib64 points to lib
       
   904     """
       
   905     if [p for p in distutils.sysconfig.get_config_vars().values()
       
   906         if isinstance(p, basestring) and 'lib64' in p]:
       
   907         logger.debug('This system uses lib64; symlinking lib64 to lib')
       
   908         assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
       
   909             "Unexpected python lib dir: %r" % lib_dir)
       
   910         lib_parent = os.path.dirname(lib_dir)
       
   911         assert os.path.basename(lib_parent) == 'lib', (
       
   912             "Unexpected parent dir: %r" % lib_parent)
       
   913         copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
       
   914 
       
   915 def resolve_interpreter(exe):
       
   916     """
       
   917     If the executable given isn't an absolute path, search $PATH for the interpreter
       
   918     """
       
   919     if os.path.abspath(exe) != exe:
       
   920         paths = os.environ.get('PATH', '').split(os.pathsep)
       
   921         for path in paths:
       
   922             if os.path.exists(os.path.join(path, exe)):
       
   923                 exe = os.path.join(path, exe)
       
   924                 break
       
   925     if not os.path.exists(exe):
       
   926         logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
       
   927         sys.exit(3)
       
   928     return exe
       
   929 
       
   930 ############################################################
       
   931 ## Relocating the environment:
       
   932 
       
   933 def make_environment_relocatable(home_dir):
       
   934     """
       
   935     Makes the already-existing environment use relative paths, and takes out
       
   936     the #!-based environment selection in scripts.
       
   937     """
       
   938     home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
       
   939     activate_this = os.path.join(bin_dir, 'activate_this.py')
       
   940     if not os.path.exists(activate_this):
       
   941         logger.fatal(
       
   942             'The environment doesn\'t have a file %s -- please re-run virtualenv '
       
   943             'on this environment to update it' % activate_this)
       
   944     fixup_scripts(home_dir)
       
   945     fixup_pth_and_egg_link(home_dir)
       
   946     ## FIXME: need to fix up distutils.cfg
       
   947 
       
   948 OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
       
   949                   'activate', 'activate.bat', 'activate_this.py']
       
   950 
       
   951 def fixup_scripts(home_dir):
       
   952     # This is what we expect at the top of scripts:
       
   953     shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
       
   954     # This is what we'll put:
       
   955     new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
       
   956     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"
       
   957     bin_dir = os.path.join(home_dir, 'bin')
       
   958     home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
       
   959     for filename in os.listdir(bin_dir):
       
   960         filename = os.path.join(bin_dir, filename)
       
   961         if not os.path.isfile(filename):
       
   962             # ignore subdirs, e.g. .svn ones.
       
   963             continue
       
   964         f = open(filename, 'rb')
       
   965         lines = f.readlines()
       
   966         f.close()
       
   967         if not lines:
       
   968             logger.warn('Script %s is an empty file' % filename)
       
   969             continue
       
   970         if not lines[0].strip().startswith(shebang):
       
   971             if os.path.basename(filename) in OK_ABS_SCRIPTS:
       
   972                 logger.debug('Cannot make script %s relative' % filename)
       
   973             elif lines[0].strip() == new_shebang:
       
   974                 logger.info('Script %s has already been made relative' % filename)
       
   975             else:
       
   976                 logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
       
   977                             % (filename, shebang))
       
   978             continue
       
   979         logger.notify('Making script %s relative' % filename)
       
   980         lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
       
   981         f = open(filename, 'wb')
       
   982         f.writelines(lines)
       
   983         f.close()
       
   984 
       
   985 def fixup_pth_and_egg_link(home_dir, sys_path=None):
       
   986     """Makes .pth and .egg-link files use relative paths"""
       
   987     home_dir = os.path.normcase(os.path.abspath(home_dir))
       
   988     if sys_path is None:
       
   989         sys_path = sys.path
       
   990     for path in sys_path:
       
   991         if not path:
       
   992             path = '.'
       
   993         if not os.path.isdir(path):
       
   994             continue
       
   995         path = os.path.normcase(os.path.abspath(path))
       
   996         if not path.startswith(home_dir):
       
   997             logger.debug('Skipping system (non-environment) directory %s' % path)
       
   998             continue
       
   999         for filename in os.listdir(path):
       
  1000             filename = os.path.join(path, filename)
       
  1001             if filename.endswith('.pth'):
       
  1002                 if not os.access(filename, os.W_OK):
       
  1003                     logger.warn('Cannot write .pth file %s, skipping' % filename)
       
  1004                 else:
       
  1005                     fixup_pth_file(filename)
       
  1006             if filename.endswith('.egg-link'):
       
  1007                 if not os.access(filename, os.W_OK):
       
  1008                     logger.warn('Cannot write .egg-link file %s, skipping' % filename)
       
  1009                 else:
       
  1010                     fixup_egg_link(filename)
       
  1011 
       
  1012 def fixup_pth_file(filename):
       
  1013     lines = []
       
  1014     prev_lines = []
       
  1015     f = open(filename)
       
  1016     prev_lines = f.readlines()
       
  1017     f.close()
       
  1018     for line in prev_lines:
       
  1019         line = line.strip()
       
  1020         if (not line or line.startswith('#') or line.startswith('import ')
       
  1021             or os.path.abspath(line) != line):
       
  1022             lines.append(line)
       
  1023         else:
       
  1024             new_value = make_relative_path(filename, line)
       
  1025             if line != new_value:
       
  1026                 logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
       
  1027             lines.append(new_value)
       
  1028     if lines == prev_lines:
       
  1029         logger.info('No changes to .pth file %s' % filename)
       
  1030         return
       
  1031     logger.notify('Making paths in .pth file %s relative' % filename)
       
  1032     f = open(filename, 'w')
       
  1033     f.write('\n'.join(lines) + '\n')
       
  1034     f.close()
       
  1035 
       
  1036 def fixup_egg_link(filename):
       
  1037     f = open(filename)
       
  1038     link = f.read().strip()
       
  1039     f.close()
       
  1040     if os.path.abspath(link) != link:
       
  1041         logger.debug('Link in %s already relative' % filename)
       
  1042         return
       
  1043     new_link = make_relative_path(filename, link)
       
  1044     logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
       
  1045     f = open(filename, 'w')
       
  1046     f.write(new_link)
       
  1047     f.close()
       
  1048 
       
  1049 def make_relative_path(source, dest, dest_is_directory=True):
       
  1050     """
       
  1051     Make a filename relative, where the filename is dest, and it is
       
  1052     being referred to from the filename source.
       
  1053 
       
  1054         >>> make_relative_path('/usr/share/something/a-file.pth',
       
  1055         ...                    '/usr/share/another-place/src/Directory')
       
  1056         '../another-place/src/Directory'
       
  1057         >>> make_relative_path('/usr/share/something/a-file.pth',
       
  1058         ...                    '/home/user/src/Directory')
       
  1059         '../../../home/user/src/Directory'
       
  1060         >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
       
  1061         './'
       
  1062     """
       
  1063     source = os.path.dirname(source)
       
  1064     if not dest_is_directory:
       
  1065         dest_filename = os.path.basename(dest)
       
  1066         dest = os.path.dirname(dest)
       
  1067     dest = os.path.normpath(os.path.abspath(dest))
       
  1068     source = os.path.normpath(os.path.abspath(source))
       
  1069     dest_parts = dest.strip(os.path.sep).split(os.path.sep)
       
  1070     source_parts = source.strip(os.path.sep).split(os.path.sep)
       
  1071     while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
       
  1072         dest_parts.pop(0)
       
  1073         source_parts.pop(0)
       
  1074     full_parts = ['..']*len(source_parts) + dest_parts
       
  1075     if not dest_is_directory:
       
  1076         full_parts.append(dest_filename)
       
  1077     if not full_parts:
       
  1078         # Special case for the current directory (otherwise it'd be '')
       
  1079         return './'
       
  1080     return os.path.sep.join(full_parts)
       
  1081 
       
  1082 
       
  1083 
       
  1084 ############################################################
       
  1085 ## Bootstrap script creation:
       
  1086 
       
  1087 def create_bootstrap_script(extra_text, python_version=''):
       
  1088     """
       
  1089     Creates a bootstrap script, which is like this script but with
       
  1090     extend_parser, adjust_options, and after_install hooks.
       
  1091 
       
  1092     This returns a string that (written to disk of course) can be used
       
  1093     as a bootstrap script with your own customizations.  The script
       
  1094     will be the standard virtualenv.py script, with your extra text
       
  1095     added (your extra text should be Python code).
       
  1096 
       
  1097     If you include these functions, they will be called:
       
  1098 
       
  1099     ``extend_parser(optparse_parser)``:
       
  1100         You can add or remove options from the parser here.
       
  1101 
       
  1102     ``adjust_options(options, args)``:
       
  1103         You can change options here, or change the args (if you accept
       
  1104         different kinds of arguments, be sure you modify ``args`` so it is
       
  1105         only ``[DEST_DIR]``).
       
  1106 
       
  1107     ``after_install(options, home_dir)``:
       
  1108 
       
  1109         After everything is installed, this function is called.  This
       
  1110         is probably the function you are most likely to use.  An
       
  1111         example would be::
       
  1112 
       
  1113             def after_install(options, home_dir):
       
  1114                 subprocess.call([join(home_dir, 'bin', 'easy_install'),
       
  1115                                  'MyPackage'])
       
  1116                 subprocess.call([join(home_dir, 'bin', 'my-package-script'),
       
  1117                                  'setup', home_dir])
       
  1118 
       
  1119         This example immediately installs a package, and runs a setup
       
  1120         script from that package.
       
  1121 
       
  1122     If you provide something like ``python_version='2.4'`` then the
       
  1123     script will start with ``#!/usr/bin/env python2.4`` instead of
       
  1124     ``#!/usr/bin/env python``.  You can use this when the script must
       
  1125     be run with a particular Python version.
       
  1126     """
       
  1127     filename = __file__
       
  1128     if filename.endswith('.pyc'):
       
  1129         filename = filename[:-1]
       
  1130     f = open(filename, 'rb')
       
  1131     content = f.read()
       
  1132     f.close()
       
  1133     py_exe = 'python%s' % python_version
       
  1134     content = (('#!/usr/bin/env %s\n' % py_exe)
       
  1135                + '## WARNING: This file is generated\n'
       
  1136                + content)
       
  1137     return content.replace('##EXT' 'END##', extra_text)
       
  1138 
       
  1139 import sys
       
  1140 sys.path.append('/Users/ymh/dev/workspace/platform/virtualenv/res/lib')
       
  1141 sys.path.append('/Users/ymh/dev/workspace/platform/virtualenv/setup/res')
       
  1142 from res_create_env import generate_install_methods
       
  1143 adjust_options, extend_parser, after_install = generate_install_methods(path_locations, '/Users/ymh/dev/workspace/platform/virtualenv/res/src', Logger, call_subprocess)
       
  1144 
       
  1145 
       
  1146 ##file site.py
       
  1147 SITE_PY = """
       
  1148 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
       
  1278 yBXo8FFND74JkgILcmKn2vJbYxD8H2/QG9E=
       
  1279 """.decode("base64").decode("zlib")
       
  1280 
       
  1281 ##file ez_setup.py
       
  1282 EZ_SETUP_PY = """
       
  1283 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
       
  1349 178BYnMUkw==
       
  1350 """.decode("base64").decode("zlib")
       
  1351 
       
  1352 ##file distribute_setup.py
       
  1353 DISTRIBUTE_SETUP_PY = """
       
  1354 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
       
  1433 """.decode("base64").decode("zlib")
       
  1434 
       
  1435 ##file activate.sh
       
  1436 ACTIVATE_SH = """
       
  1437 eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9
       
  1438 H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq
       
  1439 DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs
       
  1440 cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY
       
  1441 G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T
       
  1442 EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs
       
  1443 wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG
       
  1444 5eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/
       
  1445 JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR
       
  1446 huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx
       
  1447 Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L
       
  1448 Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw
       
  1449 WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX
       
  1450 LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2
       
  1451 """.decode("base64").decode("zlib")
       
  1452 
       
  1453 ##file activate.bat
       
  1454 ACTIVATE_BAT = """
       
  1455 eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
       
  1456 qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
       
  1457 sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
       
  1458 ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
       
  1459 """.decode("base64").decode("zlib")
       
  1460 
       
  1461 ##file deactivate.bat
       
  1462 DEACTIVATE_BAT = """
       
  1463 eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
       
  1464 FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
       
  1465 i2dASrm4rFz9XLgAwJNbyQ==
       
  1466 """.decode("base64").decode("zlib")
       
  1467 
       
  1468 ##file distutils-init.py
       
  1469 DISTUTILS_INIT = """
       
  1470 eJytVl2L6zYQffevGBKK7XavKe3bhVBo78uFSyml0IdlEVpbTtR1JCMpm6S/vjOSY0v+uO1DDbs4
       
  1471 0tF8nJk5sjz32jjQNpPhzd7H1ys3SqqjhcfCL1q18vgbN1YY2Kc/pQWlHXB4l8ZdeCfUO5x1c+nE
       
  1472 E1gNVwE1V3CxAqQDp6GVqgF3EmBd08nXLGukUfws4IDBVD13p2pYoS3rLk52ltF6hPhLS1XM4EUc
       
  1473 VsVYKzvBWPkE+WgmLzPZjkaUNmd6KVI3JRwWoRSLM6P98mMG+Dw4q+il8Ev07P7ATCNmRlfQ8/qN
       
  1474 HwVwB99Y4H0vMHAi6BWZUoEhoqXTNXdSK+A2LN6tE+fJ0E+7MhOdFSEM5lNgrJIKWXDF908wy87D
       
  1475 xE3UoHsxkegZTaHIHGNSSYfm+ntelpURvCnK7NEWBI/ap/b8Z1m232N2rj7B60V2DRM3B5NpaLSw
       
  1476 KnfwpvQVTviHOR+F88lhQyBAGlE7be6DoRNg9ldsG3218IHa6MRNU+tGBEYIggwafRk6yzsXDcVU
       
  1477 9Ua08kYxt+F3x12LRaQi52j0xx/ywFxrdMRqVevzmaummlIYEp0WsCAaX8cFb6buuLUTqEgQQ6/Q
       
  1478 04iWRoF38m/BdE8VtlBY0bURiB6KG1crpMZwc2fIjqWh+1UrkSLpWUIP8PySwLKv4qPGSVqDuMPy
       
  1479 dywQ+gS7L1irXVkm5pJsq3l+Ib1lMOvUrxI+/mBBY4KB+WpUtcO06RtzckNvQ6vYj1lGoZM2sdDG
       
  1480 fryJPYJVn/Cfka8XSqNaoLKhmOlqXMzW9+YBVp1EtIThZtOwzCRvMaARa+0xD0b2kcaJGwJsMbc7
       
  1481 hLUfY4vKvsCOBdvDnyfuRbzmXRdGTZgPF7oGQkJACWVD22IMQdhx0npt5S2f+pXO+OwH6d+hwiS5
       
  1482 7IJOjcK2emj1zBy1aONHByfAMoraw6WlrSIFTbGghqASoRCjVncYROFpXM4uYSqhGnuVeGvks4jz
       
  1483 cjnCoR5GnPW7KOh4maVbdFeoplgJ3wh3MSrAsv/QuMjOspnTKRl1fTYqqNisv7uTVnhF1GhoBFbp
       
  1484 lh+OcXN2riA5ZrYXtWxlfcDuC8U5kLoN3CCJYXGpesO6dx6rU0zGMtjU6cNlmW0Fid8Sja4ZG+Z3
       
  1485 fTPbyj+mZnZ2wSQK8RaT9Km0ySRuLpm0DkUUL0ra3WQ2BgGJ7v9I9SKqNKZ/IR4R28RHm+vEz5ic
       
  1486 nZ2IH7bfub8pU1PR3gr10W7xLTfHh6Z6bgZ7K14G7Mj/1z5J6MFo6V5e07H0Ou78dTyeI+mxKOpI
       
  1487 eC2KMSj6HKxd6Uudf/n886fPv+f++x1lbASlmjQuPz8OvGA0j7j2eCu/4bcW6SFeCuNJ0W1GQHI5
       
  1488 iwC9Ey0bjtHd9P4dPA++XxLnZDVuxvFEtlm3lf5a2c02u2LRYXHH/AOs8pIa
       
  1489 """.decode("base64").decode("zlib")
       
  1490 
       
  1491 ##file distutils.cfg
       
  1492 DISTUTILS_CFG = """
       
  1493 eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
       
  1494 xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
       
  1495 9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
       
  1496 """.decode("base64").decode("zlib")
       
  1497 
       
  1498 ##file activate_this.py
       
  1499 ACTIVATE_THIS = """
       
  1500 eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ
       
  1501 VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a
       
  1502 Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE
       
  1503 qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX
       
  1504 4lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7
       
  1505 HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n
       
  1506 xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96
       
  1507 1Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI
       
  1508 3vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU=
       
  1509 """.decode("base64").decode("zlib")
       
  1510 
       
  1511 if __name__ == '__main__':
       
  1512     main()
       
  1513 
       
  1514 ## TODO:
       
  1515 ## Copy python.exe.manifest
       
  1516 ## Monkeypatch distutils.sysconfig