图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.5 KiB

  1. import itertools
  2. import logging
  3. import os
  4. import posixpath
  5. import urllib.parse
  6. from typing import List
  7. from pip._vendor.packaging.utils import canonicalize_name
  8. from pip._internal.models.index import PyPI
  9. from pip._internal.utils.compat import has_tls
  10. from pip._internal.utils.misc import normalize_path, redact_auth_from_url
  11. logger = logging.getLogger(__name__)
  12. class SearchScope:
  13. """
  14. Encapsulates the locations that pip is configured to search.
  15. """
  16. __slots__ = ["find_links", "index_urls", "no_index"]
  17. @classmethod
  18. def create(
  19. cls,
  20. find_links: List[str],
  21. index_urls: List[str],
  22. no_index: bool,
  23. ) -> "SearchScope":
  24. """
  25. Create a SearchScope object after normalizing the `find_links`.
  26. """
  27. # Build find_links. If an argument starts with ~, it may be
  28. # a local file relative to a home directory. So try normalizing
  29. # it and if it exists, use the normalized version.
  30. # This is deliberately conservative - it might be fine just to
  31. # blindly normalize anything starting with a ~...
  32. built_find_links: List[str] = []
  33. for link in find_links:
  34. if link.startswith("~"):
  35. new_link = normalize_path(link)
  36. if os.path.exists(new_link):
  37. link = new_link
  38. built_find_links.append(link)
  39. # If we don't have TLS enabled, then WARN if anyplace we're looking
  40. # relies on TLS.
  41. if not has_tls():
  42. for link in itertools.chain(index_urls, built_find_links):
  43. parsed = urllib.parse.urlparse(link)
  44. if parsed.scheme == "https":
  45. logger.warning(
  46. "pip is configured with locations that require "
  47. "TLS/SSL, however the ssl module in Python is not "
  48. "available."
  49. )
  50. break
  51. return cls(
  52. find_links=built_find_links,
  53. index_urls=index_urls,
  54. no_index=no_index,
  55. )
  56. def __init__(
  57. self,
  58. find_links: List[str],
  59. index_urls: List[str],
  60. no_index: bool,
  61. ) -> None:
  62. self.find_links = find_links
  63. self.index_urls = index_urls
  64. self.no_index = no_index
  65. def get_formatted_locations(self) -> str:
  66. lines = []
  67. redacted_index_urls = []
  68. if self.index_urls and self.index_urls != [PyPI.simple_url]:
  69. for url in self.index_urls:
  70. redacted_index_url = redact_auth_from_url(url)
  71. # Parse the URL
  72. purl = urllib.parse.urlsplit(redacted_index_url)
  73. # URL is generally invalid if scheme and netloc is missing
  74. # there are issues with Python and URL parsing, so this test
  75. # is a bit crude. See bpo-20271, bpo-23505. Python doesn't
  76. # always parse invalid URLs correctly - it should raise
  77. # exceptions for malformed URLs
  78. if not purl.scheme and not purl.netloc:
  79. logger.warning(
  80. 'The index url "%s" seems invalid, please provide a scheme.',
  81. redacted_index_url,
  82. )
  83. redacted_index_urls.append(redacted_index_url)
  84. lines.append(
  85. "Looking in indexes: {}".format(", ".join(redacted_index_urls))
  86. )
  87. if self.find_links:
  88. lines.append(
  89. "Looking in links: {}".format(
  90. ", ".join(redact_auth_from_url(url) for url in self.find_links)
  91. )
  92. )
  93. return "\n".join(lines)
  94. def get_index_urls_locations(self, project_name: str) -> List[str]:
  95. """Returns the locations found via self.index_urls
  96. Checks the url_name on the main (first in the list) index and
  97. use this url_name to produce all locations
  98. """
  99. def mkurl_pypi_url(url: str) -> str:
  100. loc = posixpath.join(
  101. url, urllib.parse.quote(canonicalize_name(project_name))
  102. )
  103. # For maximum compatibility with easy_install, ensure the path
  104. # ends in a trailing slash. Although this isn't in the spec
  105. # (and PyPI can handle it without the slash) some other index
  106. # implementations might break if they relied on easy_install's
  107. # behavior.
  108. if not loc.endswith("/"):
  109. loc = loc + "/"
  110. return loc
  111. return [mkurl_pypi_url(url) for url in self.index_urls]