wheel.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import
  3. import logging
  4. import os
  5. import warnings
  6. from pip.basecommand import Command
  7. from pip.index import PackageFinder
  8. from pip.exceptions import CommandError, PreviousBuildDirError
  9. from pip.req import InstallRequirement, RequirementSet, parse_requirements
  10. from pip.utils import import_or_raise, normalize_path
  11. from pip.utils.build import BuildDirectory
  12. from pip.utils.deprecation import RemovedInPip7Warning, RemovedInPip8Warning
  13. from pip.wheel import WheelBuilder
  14. from pip import cmdoptions
  15. DEFAULT_WHEEL_DIR = os.path.join(normalize_path(os.curdir), 'wheelhouse')
  16. logger = logging.getLogger(__name__)
  17. class WheelCommand(Command):
  18. """
  19. Build Wheel archives for your requirements and dependencies.
  20. Wheel is a built-package format, and offers the advantage of not
  21. recompiling your software during every install. For more details, see the
  22. wheel docs: http://wheel.readthedocs.org/en/latest.
  23. Requirements: setuptools>=0.8, and wheel.
  24. 'pip wheel' uses the bdist_wheel setuptools extension from the wheel
  25. package to build individual wheels.
  26. """
  27. name = 'wheel'
  28. usage = """
  29. %prog [options] <requirement specifier> ...
  30. %prog [options] -r <requirements file> ...
  31. %prog [options] [-e] <vcs project url> ...
  32. %prog [options] [-e] <local project path> ...
  33. %prog [options] <archive url/path> ..."""
  34. summary = 'Build wheels from your requirements.'
  35. def __init__(self, *args, **kw):
  36. super(WheelCommand, self).__init__(*args, **kw)
  37. cmd_opts = self.cmd_opts
  38. cmd_opts.add_option(
  39. '-w', '--wheel-dir',
  40. dest='wheel_dir',
  41. metavar='dir',
  42. default=DEFAULT_WHEEL_DIR,
  43. help=("Build wheels into <dir>, where the default is "
  44. "'<cwd>/wheelhouse'."),
  45. )
  46. cmd_opts.add_option(cmdoptions.use_wheel.make())
  47. cmd_opts.add_option(cmdoptions.no_use_wheel.make())
  48. cmd_opts.add_option(
  49. '--build-option',
  50. dest='build_options',
  51. metavar='options',
  52. action='append',
  53. help="Extra arguments to be supplied to 'setup.py bdist_wheel'.")
  54. cmd_opts.add_option(cmdoptions.editable.make())
  55. cmd_opts.add_option(cmdoptions.requirements.make())
  56. cmd_opts.add_option(cmdoptions.download_cache.make())
  57. cmd_opts.add_option(cmdoptions.src.make())
  58. cmd_opts.add_option(cmdoptions.no_deps.make())
  59. cmd_opts.add_option(cmdoptions.build_dir.make())
  60. cmd_opts.add_option(
  61. '--global-option',
  62. dest='global_options',
  63. action='append',
  64. metavar='options',
  65. help="Extra global options to be supplied to the setup.py "
  66. "call before the 'bdist_wheel' command.")
  67. cmd_opts.add_option(
  68. '--pre',
  69. action='store_true',
  70. default=False,
  71. help=("Include pre-release and development versions. By default, "
  72. "pip only finds stable versions."),
  73. )
  74. cmd_opts.add_option(cmdoptions.no_clean.make())
  75. index_opts = cmdoptions.make_option_group(
  76. cmdoptions.index_group,
  77. self.parser,
  78. )
  79. self.parser.insert_option_group(0, index_opts)
  80. self.parser.insert_option_group(0, cmd_opts)
  81. def check_required_packages(self):
  82. import_or_raise(
  83. 'wheel.bdist_wheel',
  84. CommandError,
  85. "'pip wheel' requires the 'wheel' package. To fix this, run: "
  86. "pip install wheel"
  87. )
  88. pkg_resources = import_or_raise(
  89. 'pkg_resources',
  90. CommandError,
  91. "'pip wheel' requires setuptools >= 0.8 for dist-info support."
  92. " To fix this, run: pip install --upgrade setuptools"
  93. )
  94. if not hasattr(pkg_resources, 'DistInfoDistribution'):
  95. raise CommandError(
  96. "'pip wheel' requires setuptools >= 0.8 for dist-info "
  97. "support. To fix this, run: pip install --upgrade "
  98. "setuptools"
  99. )
  100. def run(self, options, args):
  101. self.check_required_packages()
  102. index_urls = [options.index_url] + options.extra_index_urls
  103. if options.no_index:
  104. logger.info('Ignoring indexes: %s', ','.join(index_urls))
  105. index_urls = []
  106. if options.use_mirrors:
  107. warnings.warn(
  108. "--use-mirrors has been deprecated and will be removed in the "
  109. "future. Explicit uses of --index-url and/or --extra-index-url"
  110. " is suggested.",
  111. RemovedInPip7Warning,
  112. )
  113. if options.mirrors:
  114. warnings.warn(
  115. "--mirrors has been deprecated and will be removed in the "
  116. "future. Explicit uses of --index-url and/or --extra-index-url"
  117. " is suggested.",
  118. RemovedInPip7Warning,
  119. )
  120. index_urls += options.mirrors
  121. if options.download_cache:
  122. warnings.warn(
  123. "--download-cache has been deprecated and will be removed in "
  124. "the future. Pip now automatically uses and configures its "
  125. "cache.",
  126. RemovedInPip8Warning,
  127. )
  128. if options.build_dir:
  129. options.build_dir = os.path.abspath(options.build_dir)
  130. with self._build_session(options) as session:
  131. finder = PackageFinder(
  132. find_links=options.find_links,
  133. index_urls=index_urls,
  134. use_wheel=options.use_wheel,
  135. allow_external=options.allow_external,
  136. allow_unverified=options.allow_unverified,
  137. allow_all_external=options.allow_all_external,
  138. allow_all_prereleases=options.pre,
  139. trusted_hosts=options.trusted_hosts,
  140. process_dependency_links=options.process_dependency_links,
  141. session=session,
  142. )
  143. build_delete = (not (options.no_clean or options.build_dir))
  144. with BuildDirectory(options.build_dir,
  145. delete=build_delete) as build_dir:
  146. requirement_set = RequirementSet(
  147. build_dir=build_dir,
  148. src_dir=options.src_dir,
  149. download_dir=None,
  150. ignore_dependencies=options.ignore_dependencies,
  151. ignore_installed=True,
  152. isolated=options.isolated_mode,
  153. session=session,
  154. wheel_download_dir=options.wheel_dir
  155. )
  156. # make the wheelhouse
  157. options.wheel_dir = normalize_path(options.wheel_dir)
  158. if not os.path.exists(options.wheel_dir):
  159. os.makedirs(options.wheel_dir)
  160. # parse args and/or requirements files
  161. for name in args:
  162. requirement_set.add_requirement(
  163. InstallRequirement.from_line(
  164. name, None, isolated=options.isolated_mode,
  165. )
  166. )
  167. for name in options.editables:
  168. requirement_set.add_requirement(
  169. InstallRequirement.from_editable(
  170. name,
  171. default_vcs=options.default_vcs,
  172. isolated=options.isolated_mode,
  173. )
  174. )
  175. for filename in options.requirements:
  176. for req in parse_requirements(
  177. filename,
  178. finder=finder,
  179. options=options,
  180. session=session):
  181. requirement_set.add_requirement(req)
  182. # fail if no requirements
  183. if not requirement_set.has_requirements:
  184. logger.error(
  185. "You must give at least one requirement to %s "
  186. "(see \"pip help %s\")",
  187. self.name, self.name,
  188. )
  189. return
  190. try:
  191. # build wheels
  192. wb = WheelBuilder(
  193. requirement_set,
  194. finder,
  195. options.wheel_dir,
  196. build_options=options.build_options or [],
  197. global_options=options.global_options or [],
  198. )
  199. if not wb.build():
  200. raise CommandError(
  201. "Failed to build one or more wheels"
  202. )
  203. except PreviousBuildDirError:
  204. options.no_clean = True
  205. raise
  206. finally:
  207. if not options.no_clean:
  208. requirement_set.cleanup_files()