PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/tools/bootstrap.py

https://bitbucket.org/Chris2048/watchdog
Python | 278 lines | 222 code | 21 blank | 35 comment | 57 complexity | 836044bed0341c5b7a8989a929ff01f6 MD5 | raw file
  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, shutil, sys, tempfile, textwrap
  20. try:
  21. import urllib.request as urllib2
  22. except ImportError:
  23. import urllib2
  24. import subprocess
  25. from optparse import OptionParser
  26. if sys.platform == 'win32':
  27. def quote(c):
  28. if ' ' in c:
  29. return '"%s"' % c # work around spawn lamosity on windows
  30. else:
  31. return c
  32. else:
  33. quote = str
  34. # See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
  35. stdout, stderr = subprocess.Popen(
  36. [sys.executable, '-S', '-c',
  37. 'try:\n'
  38. ' import pickle\n'
  39. 'except ImportError:\n'
  40. ' print(1)\n'
  41. 'else:\n'
  42. ' print(0)\n'],
  43. stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
  44. has_broken_dash_S = bool(int(stdout.strip()))
  45. # In order to be more robust in the face of system Pythons, we want to
  46. # run without site-packages loaded. This is somewhat tricky, in
  47. # particular because Python 2.6's distutils imports site, so starting
  48. # with the -S flag is not sufficient. However, we'll start with that:
  49. if not has_broken_dash_S and 'site' in sys.modules:
  50. # We will restart with python -S.
  51. args = sys.argv[:]
  52. args[0:0] = [sys.executable, '-S']
  53. args = list(map(quote, args))
  54. os.execv(sys.executable, args)
  55. # Now we are running with -S. We'll get the clean sys.path, import site
  56. # because distutils will do it later, and then reset the path and clean
  57. # out any namespace packages from site-packages that might have been
  58. # loaded by .pth files.
  59. clean_path = sys.path[:]
  60. import site
  61. sys.path[:] = clean_path
  62. for k, v in list(sys.modules.items()):
  63. if k in ('setuptools', 'pkg_resources') or (
  64. hasattr(v, '__path__') and
  65. len(v.__path__)==1 and
  66. not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
  67. # This is a namespace package. Remove it.
  68. sys.modules.pop(k)
  69. is_jython = sys.platform.startswith('java')
  70. setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
  71. distribute_source = 'http://python-distribute.org/distribute_setup.py'
  72. # parsing arguments
  73. def normalize_to_url(option, opt_str, value, parser):
  74. if value:
  75. if '://' not in value: # It doesn't smell like a URL.
  76. value = 'file://%s' % (
  77. urllib2.pathname2url(
  78. os.path.abspath(os.path.expanduser(value))),)
  79. if opt_str == '--download-base' and not value.endswith('/'):
  80. # Download base needs a trailing slash to make the world happy.
  81. value += '/'
  82. else:
  83. value = None
  84. name = opt_str[2:].replace('-', '_')
  85. setattr(parser.values, name, value)
  86. usage = '''\
  87. [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
  88. Bootstraps a buildout-based project.
  89. Simply run this script in a directory containing a buildout.cfg, using the
  90. Python that you want bin/buildout to use.
  91. Note that by using --setup-source and --download-base to point to
  92. local resources, you can keep this script from going over the network.
  93. '''
  94. parser = OptionParser(usage=usage)
  95. parser.add_option("-v", "--version", dest="version",
  96. help="use a specific zc.buildout version")
  97. parser.add_option("--setup-version", dest="setup_version",
  98. help="The version of setuptools or distribute to use.")
  99. parser.add_option("-d", "--distribute",
  100. action="store_true", dest="use_distribute",
  101. default= sys.version_info[0] >= 3,
  102. help="Use Distribute rather than Setuptools.")
  103. parser.add_option("--setup-source", action="callback", dest="setup_source",
  104. callback=normalize_to_url, nargs=1, type="string",
  105. help=("Specify a URL or file location for the setup file. "
  106. "If you use Setuptools, this will default to " +
  107. setuptools_source + "; if you use Distribute, this "
  108. "will default to " + distribute_source +"."))
  109. parser.add_option("--download-base", action="callback", dest="download_base",
  110. callback=normalize_to_url, nargs=1, type="string",
  111. help=("Specify a URL or directory for downloading "
  112. "zc.buildout and either Setuptools or Distribute. "
  113. "Defaults to PyPI."))
  114. parser.add_option("--eggs",
  115. help=("Specify a directory for storing eggs. Defaults to "
  116. "a temporary directory that is deleted when the "
  117. "bootstrap script completes."))
  118. parser.add_option("-t", "--accept-buildout-test-releases",
  119. dest='accept_buildout_test_releases',
  120. action="store_true",
  121. default=sys.version_info[0] > 2,
  122. help=("Normally, if you do not specify a --version, the "
  123. "bootstrap script and buildout gets the newest "
  124. "*final* versions of zc.buildout and its recipes and "
  125. "extensions for you. If you use this flag, "
  126. "bootstrap and buildout will get the newest releases "
  127. "even if they are alphas or betas."))
  128. parser.add_option("-c", None, action="store", dest="config_file",
  129. help=("Specify the path to the buildout configuration "
  130. "file to be used."))
  131. options, args = parser.parse_args()
  132. # if -c was provided, we push it back into args for buildout's main function
  133. if options.config_file is not None:
  134. args += ['-c', options.config_file]
  135. if options.eggs:
  136. eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
  137. else:
  138. eggs_dir = tempfile.mkdtemp()
  139. if options.setup_source is None:
  140. if options.use_distribute:
  141. options.setup_source = distribute_source
  142. else:
  143. options.setup_source = setuptools_source
  144. if options.accept_buildout_test_releases:
  145. args.append('buildout:accept-buildout-test-releases=true')
  146. args.append('bootstrap')
  147. try:
  148. import pkg_resources
  149. import setuptools # A flag. Sometimes pkg_resources is installed alone.
  150. if not hasattr(pkg_resources, '_distribute'):
  151. raise ImportError
  152. except ImportError:
  153. ez_code = urllib2.urlopen(
  154. options.setup_source).read().replace('\r\n'.encode(), '\n'.encode())
  155. ez = {}
  156. exec(ez_code, ez)
  157. setup_args = dict(to_dir=eggs_dir, download_delay=0)
  158. if options.download_base:
  159. setup_args['download_base'] = options.download_base
  160. if options.setup_version:
  161. setup_args['version'] = options.setup_version
  162. if options.use_distribute:
  163. setup_args['no_fake'] = True
  164. ez['use_setuptools'](**setup_args)
  165. if 'pkg_resources' in sys.modules:
  166. if sys.version_info[0] >= 3:
  167. import imp
  168. reload_ = imp.reload
  169. else:
  170. reload_ = reload
  171. reload_(sys.modules['pkg_resources'])
  172. import pkg_resources
  173. # This does not (always?) update the default working set. We will
  174. # do it.
  175. for path in sys.path:
  176. if path not in pkg_resources.working_set.entries:
  177. pkg_resources.working_set.add_entry(path)
  178. cmd = [quote(sys.executable),
  179. '-c',
  180. quote('from setuptools.command.easy_install import main; main()'),
  181. '-mqNxd',
  182. quote(eggs_dir)]
  183. if not has_broken_dash_S:
  184. cmd.insert(1, '-S')
  185. find_links = options.download_base
  186. if not find_links:
  187. find_links = os.environ.get('bootstrap-testing-find-links')
  188. if find_links:
  189. cmd.extend(['-f', quote(find_links)])
  190. if options.use_distribute:
  191. setup_requirement = 'distribute'
  192. else:
  193. setup_requirement = 'setuptools'
  194. ws = pkg_resources.working_set
  195. setup_requirement_path = ws.find(
  196. pkg_resources.Requirement.parse(setup_requirement)).location
  197. env = dict(
  198. os.environ,
  199. PYTHONPATH=setup_requirement_path)
  200. requirement = 'zc.buildout'
  201. version = options.version
  202. if version is None and not options.accept_buildout_test_releases:
  203. # Figure out the most recent final version of zc.buildout.
  204. import setuptools.package_index
  205. _final_parts = '*final-', '*final'
  206. def _final_version(parsed_version):
  207. for part in parsed_version:
  208. if (part[:1] == '*') and (part not in _final_parts):
  209. return False
  210. return True
  211. index = setuptools.package_index.PackageIndex(
  212. search_path=[setup_requirement_path])
  213. if find_links:
  214. index.add_find_links((find_links,))
  215. req = pkg_resources.Requirement.parse(requirement)
  216. if index.obtain(req) is not None:
  217. best = []
  218. bestv = None
  219. for dist in index[req.project_name]:
  220. distv = dist.parsed_version
  221. if _final_version(distv):
  222. if bestv is None or distv > bestv:
  223. best = [dist]
  224. bestv = distv
  225. elif distv == bestv:
  226. best.append(dist)
  227. if best:
  228. best.sort()
  229. version = best[-1].version
  230. if version:
  231. requirement = '=='.join((requirement, version))
  232. cmd.append(requirement)
  233. if is_jython:
  234. import subprocess
  235. exitcode = subprocess.Popen(cmd, env=env).wait()
  236. else: # Windows prefers this, apparently; otherwise we would prefer subprocess
  237. exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
  238. if exitcode != 0:
  239. sys.stdout.flush()
  240. sys.stderr.flush()
  241. print("An error occurred when trying to install zc.buildout. "
  242. "Look above this message for any errors that "
  243. "were output by easy_install.")
  244. sys.exit(exitcode)
  245. ws.add_entry(eggs_dir)
  246. ws.require(requirement)
  247. import zc.buildout.buildout
  248. zc.buildout.buildout.main(args)
  249. if not options.eggs: # clean up temporary egg directory
  250. shutil.rmtree(eggs_dir)