bootstrap.py
changeset 474 7bb070e90138
equal deleted inserted replaced
-1:000000000000 474:7bb070e90138
       
     1 ##############################################################################
       
     2 #
       
     3 # Copyright (c) 2006 Zope Foundation and Contributors.
       
     4 # All Rights Reserved.
       
     5 #
       
     6 # This software is subject to the provisions of the Zope Public License,
       
     7 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
       
     8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
       
     9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
       
    11 # FOR A PARTICULAR PURPOSE.
       
    12 #
       
    13 ##############################################################################
       
    14 """Bootstrap a buildout-based project
       
    15 
       
    16 Simply run this script in a directory containing a buildout.cfg.
       
    17 The script accepts buildout command-line options, so you can
       
    18 use the -c option to specify an alternate configuration file.
       
    19 """
       
    20 
       
    21 import os
       
    22 import shutil
       
    23 import sys
       
    24 import tempfile
       
    25 
       
    26 from optparse import OptionParser
       
    27 
       
    28 __version__ = '2015-07-01'
       
    29 # See zc.buildout's changelog if this version is up to date.
       
    30 
       
    31 tmpeggs = tempfile.mkdtemp(prefix='bootstrap-')
       
    32 
       
    33 usage = '''\
       
    34 [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
       
    35 
       
    36 Bootstraps a buildout-based project.
       
    37 
       
    38 Simply run this script in a directory containing a buildout.cfg, using the
       
    39 Python that you want bin/buildout to use.
       
    40 
       
    41 Note that by using --find-links to point to local resources, you can keep
       
    42 this script from going over the network.
       
    43 '''
       
    44 
       
    45 parser = OptionParser(usage=usage)
       
    46 parser.add_option("--version",
       
    47                   action="store_true", default=False,
       
    48                   help=("Return bootstrap.py version."))
       
    49 parser.add_option("-t", "--accept-buildout-test-releases",
       
    50                   dest='accept_buildout_test_releases',
       
    51                   action="store_true", default=False,
       
    52                   help=("Normally, if you do not specify a --buildout-version, "
       
    53                         "the bootstrap script and buildout gets the newest "
       
    54                         "*final* versions of zc.buildout and its recipes and "
       
    55                         "extensions for you.  If you use this flag, "
       
    56                         "bootstrap and buildout will get the newest releases "
       
    57                         "even if they are alphas or betas."))
       
    58 parser.add_option("-c", "--config-file",
       
    59                   help=("Specify the path to the buildout configuration "
       
    60                         "file to be used."))
       
    61 parser.add_option("-f", "--find-links",
       
    62                   help=("Specify a URL to search for buildout releases"))
       
    63 parser.add_option("--allow-site-packages",
       
    64                   action="store_true", default=False,
       
    65                   help=("Let bootstrap.py use existing site packages"))
       
    66 parser.add_option("--buildout-version",
       
    67                   help="Use a specific zc.buildout version")
       
    68 parser.add_option("--setuptools-version",
       
    69                   help="Use a specific setuptools version")
       
    70 parser.add_option("--setuptools-to-dir",
       
    71                   help=("Allow for re-use of existing directory of "
       
    72                         "setuptools versions"))
       
    73 
       
    74 options, args = parser.parse_args()
       
    75 if options.version:
       
    76     print("bootstrap.py version %s" % __version__)
       
    77     sys.exit(0)
       
    78 
       
    79 
       
    80 ######################################################################
       
    81 # load/install setuptools
       
    82 
       
    83 try:
       
    84     from urllib.request import urlopen
       
    85 except ImportError:
       
    86     from urllib2 import urlopen
       
    87 
       
    88 ez = {}
       
    89 if os.path.exists('ez_setup.py'):
       
    90     exec(open('ez_setup.py').read(), ez)
       
    91 else:
       
    92     exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
       
    93 
       
    94 if not options.allow_site_packages:
       
    95     # ez_setup imports site, which adds site packages
       
    96     # this will remove them from the path to ensure that incompatible versions
       
    97     # of setuptools are not in the path
       
    98     import site
       
    99     # inside a virtualenv, there is no 'getsitepackages'.
       
   100     # We can't remove these reliably
       
   101     if hasattr(site, 'getsitepackages'):
       
   102         for sitepackage_path in site.getsitepackages():
       
   103             # Strip all site-packages directories from sys.path that
       
   104             # are not sys.prefix; this is because on Windows
       
   105             # sys.prefix is a site-package directory.
       
   106             if sitepackage_path != sys.prefix:
       
   107                 sys.path[:] = [x for x in sys.path
       
   108                                if sitepackage_path not in x]
       
   109 
       
   110 setup_args = dict(to_dir=tmpeggs, download_delay=0)
       
   111 
       
   112 if options.setuptools_version is not None:
       
   113     setup_args['version'] = options.setuptools_version
       
   114 if options.setuptools_to_dir is not None:
       
   115     setup_args['to_dir'] = options.setuptools_to_dir
       
   116 
       
   117 ez['use_setuptools'](**setup_args)
       
   118 import setuptools
       
   119 import pkg_resources
       
   120 
       
   121 # This does not (always?) update the default working set.  We will
       
   122 # do it.
       
   123 for path in sys.path:
       
   124     if path not in pkg_resources.working_set.entries:
       
   125         pkg_resources.working_set.add_entry(path)
       
   126 
       
   127 ######################################################################
       
   128 # Install buildout
       
   129 
       
   130 ws = pkg_resources.working_set
       
   131 
       
   132 setuptools_path = ws.find(
       
   133     pkg_resources.Requirement.parse('setuptools')).location
       
   134 
       
   135 # Fix sys.path here as easy_install.pth added before PYTHONPATH
       
   136 cmd = [sys.executable, '-c',
       
   137        'import sys; sys.path[0:0] = [%r]; ' % setuptools_path +
       
   138        'from setuptools.command.easy_install import main; main()',
       
   139        '-mZqNxd', tmpeggs]
       
   140 
       
   141 find_links = os.environ.get(
       
   142     'bootstrap-testing-find-links',
       
   143     options.find_links or
       
   144     ('http://downloads.buildout.org/'
       
   145      if options.accept_buildout_test_releases else None)
       
   146     )
       
   147 if find_links:
       
   148     cmd.extend(['-f', find_links])
       
   149 
       
   150 requirement = 'zc.buildout'
       
   151 version = options.buildout_version
       
   152 if version is None and not options.accept_buildout_test_releases:
       
   153     # Figure out the most recent final version of zc.buildout.
       
   154     import setuptools.package_index
       
   155     _final_parts = '*final-', '*final'
       
   156 
       
   157     def _final_version(parsed_version):
       
   158         try:
       
   159             return not parsed_version.is_prerelease
       
   160         except AttributeError:
       
   161             # Older setuptools
       
   162             for part in parsed_version:
       
   163                 if (part[:1] == '*') and (part not in _final_parts):
       
   164                     return False
       
   165             return True
       
   166 
       
   167     index = setuptools.package_index.PackageIndex(
       
   168         search_path=[setuptools_path])
       
   169     if find_links:
       
   170         index.add_find_links((find_links,))
       
   171     req = pkg_resources.Requirement.parse(requirement)
       
   172     if index.obtain(req) is not None:
       
   173         best = []
       
   174         bestv = None
       
   175         for dist in index[req.project_name]:
       
   176             distv = dist.parsed_version
       
   177             if _final_version(distv):
       
   178                 if bestv is None or distv > bestv:
       
   179                     best = [dist]
       
   180                     bestv = distv
       
   181                 elif distv == bestv:
       
   182                     best.append(dist)
       
   183         if best:
       
   184             best.sort()
       
   185             version = best[-1].version
       
   186 if version:
       
   187     requirement = '=='.join((requirement, version))
       
   188 cmd.append(requirement)
       
   189 
       
   190 import subprocess
       
   191 if subprocess.call(cmd) != 0:
       
   192     raise Exception(
       
   193         "Failed to execute command:\n%s" % repr(cmd)[1:-1])
       
   194 
       
   195 ######################################################################
       
   196 # Import and run buildout
       
   197 
       
   198 ws.add_entry(tmpeggs)
       
   199 ws.require(requirement)
       
   200 import zc.buildout.buildout
       
   201 
       
   202 if not [a for a in args if '=' not in a]:
       
   203     args.append('bootstrap')
       
   204 
       
   205 # if -c was provided, we push it back into args for buildout' main function
       
   206 if options.config_file is not None:
       
   207     args[0:0] = ['-c', options.config_file]
       
   208 
       
   209 zc.buildout.buildout.main(args)
       
   210 shutil.rmtree(tmpeggs)