bootstrap.py 7.3KB

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