Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

151 linhas
5.0 KiB

  1. from __future__ import annotations
  2. import glob
  3. import os
  4. import subprocess
  5. import sys
  6. import tempfile
  7. from functools import partial
  8. from pkg_resources import Distribution
  9. from . import _reqs
  10. from ._reqs import _StrOrIter
  11. from .warnings import SetuptoolsDeprecationWarning
  12. from .wheel import Wheel
  13. from distutils import log
  14. from distutils.errors import DistutilsError
  15. def _fixup_find_links(find_links):
  16. """Ensure find-links option end-up being a list of strings."""
  17. if isinstance(find_links, str):
  18. return find_links.split()
  19. assert isinstance(find_links, (tuple, list))
  20. return find_links
  21. def fetch_build_egg(dist, req):
  22. """Fetch an egg needed for building.
  23. Use pip/wheel to fetch/build a wheel."""
  24. _DeprecatedInstaller.emit()
  25. _warn_wheel_not_available(dist)
  26. return _fetch_build_egg_no_warn(dist, req)
  27. def _fetch_build_eggs(dist, requires: _StrOrIter) -> list[Distribution]:
  28. import pkg_resources # Delay import to avoid unnecessary side-effects
  29. _DeprecatedInstaller.emit(stacklevel=3)
  30. _warn_wheel_not_available(dist)
  31. resolved_dists = pkg_resources.working_set.resolve(
  32. _reqs.parse(requires, pkg_resources.Requirement), # required for compatibility
  33. installer=partial(_fetch_build_egg_no_warn, dist), # avoid warning twice
  34. replace_conflicting=True,
  35. )
  36. for dist in resolved_dists:
  37. pkg_resources.working_set.add(dist, replace=True)
  38. return resolved_dists
  39. def _fetch_build_egg_no_warn(dist, req): # noqa: C901 # is too complex (16) # FIXME
  40. import pkg_resources # Delay import to avoid unnecessary side-effects
  41. # Ignore environment markers; if supplied, it is required.
  42. req = strip_marker(req)
  43. # Take easy_install options into account, but do not override relevant
  44. # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll
  45. # take precedence.
  46. opts = dist.get_option_dict('easy_install')
  47. if 'allow_hosts' in opts:
  48. raise DistutilsError(
  49. 'the `allow-hosts` option is not supported '
  50. 'when using pip to install requirements.'
  51. )
  52. quiet = 'PIP_QUIET' not in os.environ and 'PIP_VERBOSE' not in os.environ
  53. if 'PIP_INDEX_URL' in os.environ:
  54. index_url = None
  55. elif 'index_url' in opts:
  56. index_url = opts['index_url'][1]
  57. else:
  58. index_url = None
  59. find_links = (
  60. _fixup_find_links(opts['find_links'][1])[:] if 'find_links' in opts else []
  61. )
  62. if dist.dependency_links:
  63. find_links.extend(dist.dependency_links)
  64. eggs_dir = os.path.realpath(dist.get_egg_cache_dir())
  65. environment = pkg_resources.Environment()
  66. for egg_dist in pkg_resources.find_distributions(eggs_dir):
  67. if egg_dist in req and environment.can_add(egg_dist):
  68. return egg_dist
  69. with tempfile.TemporaryDirectory() as tmpdir:
  70. cmd = [
  71. sys.executable,
  72. '-m',
  73. 'pip',
  74. '--disable-pip-version-check',
  75. 'wheel',
  76. '--no-deps',
  77. '-w',
  78. tmpdir,
  79. ]
  80. if quiet:
  81. cmd.append('--quiet')
  82. if index_url is not None:
  83. cmd.extend(('--index-url', index_url))
  84. for link in find_links or []:
  85. cmd.extend(('--find-links', link))
  86. # If requirement is a PEP 508 direct URL, directly pass
  87. # the URL to pip, as `req @ url` does not work on the
  88. # command line.
  89. cmd.append(req.url or str(req))
  90. try:
  91. subprocess.check_call(cmd)
  92. except subprocess.CalledProcessError as e:
  93. raise DistutilsError(str(e)) from e
  94. wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0])
  95. dist_location = os.path.join(eggs_dir, wheel.egg_name())
  96. wheel.install_as_egg(dist_location)
  97. dist_metadata = pkg_resources.PathMetadata(
  98. dist_location, os.path.join(dist_location, 'EGG-INFO')
  99. )
  100. return pkg_resources.Distribution.from_filename(
  101. dist_location, metadata=dist_metadata
  102. )
  103. def strip_marker(req):
  104. """
  105. Return a new requirement without the environment marker to avoid
  106. calling pip with something like `babel; extra == "i18n"`, which
  107. would always be ignored.
  108. """
  109. import pkg_resources # Delay import to avoid unnecessary side-effects
  110. # create a copy to avoid mutating the input
  111. req = pkg_resources.Requirement.parse(str(req))
  112. req.marker = None
  113. return req
  114. def _warn_wheel_not_available(dist):
  115. import pkg_resources # Delay import to avoid unnecessary side-effects
  116. try:
  117. pkg_resources.get_distribution('wheel')
  118. except pkg_resources.DistributionNotFound:
  119. dist.announce('WARNING: The wheel package is not available.', log.WARN)
  120. class _DeprecatedInstaller(SetuptoolsDeprecationWarning):
  121. _SUMMARY = "setuptools.installer and fetch_build_eggs are deprecated."
  122. _DETAILS = """
  123. Requirements should be satisfied by a PEP 517 installer.
  124. If you are using pip, you can try `pip install --use-pep517`.
  125. """
  126. # _DUE_DATE not decided yet