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.

locations.py 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. """Locations where we look for configs, install stuff, etc"""
  2. from __future__ import absolute_import
  3. import os
  4. import os.path
  5. import platform
  6. import site
  7. import sys
  8. import sysconfig
  9. from distutils import sysconfig as distutils_sysconfig
  10. from distutils.command.install import SCHEME_KEYS # type: ignore
  11. from pip._internal.utils import appdirs
  12. from pip._internal.utils.compat import WINDOWS, expanduser
  13. from pip._internal.utils.typing import MYPY_CHECK_RUNNING
  14. if MYPY_CHECK_RUNNING:
  15. from typing import Any, Union, Dict, List, Optional # noqa: F401
  16. # Application Directories
  17. USER_CACHE_DIR = appdirs.user_cache_dir("pip")
  18. DELETE_MARKER_MESSAGE = '''\
  19. This file is placed here by pip to indicate the source was put
  20. here by pip.
  21. Once this package is successfully installed this source code will be
  22. deleted (unless you remove this file).
  23. '''
  24. PIP_DELETE_MARKER_FILENAME = 'pip-delete-this-directory.txt'
  25. def write_delete_marker_file(directory):
  26. # type: (str) -> None
  27. """
  28. Write the pip delete marker file into this directory.
  29. """
  30. filepath = os.path.join(directory, PIP_DELETE_MARKER_FILENAME)
  31. with open(filepath, 'w') as marker_fp:
  32. marker_fp.write(DELETE_MARKER_MESSAGE)
  33. def running_under_virtualenv():
  34. # type: () -> bool
  35. """
  36. Return True if we're running inside a virtualenv, False otherwise.
  37. """
  38. if hasattr(sys, 'real_prefix'):
  39. return True
  40. elif sys.prefix != getattr(sys, "base_prefix", sys.prefix):
  41. return True
  42. return False
  43. def virtualenv_no_global():
  44. # type: () -> bool
  45. """
  46. Return True if in a venv and no system site packages.
  47. """
  48. # this mirrors the logic in virtualenv.py for locating the
  49. # no-global-site-packages.txt file
  50. site_mod_dir = os.path.dirname(os.path.abspath(site.__file__))
  51. no_global_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt')
  52. if running_under_virtualenv() and os.path.isfile(no_global_file):
  53. return True
  54. else:
  55. return False
  56. if running_under_virtualenv():
  57. src_prefix = os.path.join(sys.prefix, 'src')
  58. else:
  59. # FIXME: keep src in cwd for now (it is not a temporary folder)
  60. try:
  61. src_prefix = os.path.join(os.getcwd(), 'src')
  62. except OSError:
  63. # In case the current working directory has been renamed or deleted
  64. sys.exit(
  65. "The folder you are executing pip from can no longer be found."
  66. )
  67. # under macOS + virtualenv sys.prefix is not properly resolved
  68. # it is something like /path/to/python/bin/..
  69. # Note: using realpath due to tmp dirs on OSX being symlinks
  70. src_prefix = os.path.abspath(src_prefix)
  71. # FIXME doesn't account for venv linked to global site-packages
  72. site_packages = sysconfig.get_path("purelib") # type: Optional[str]
  73. # This is because of a bug in PyPy's sysconfig module, see
  74. # https://bitbucket.org/pypy/pypy/issues/2506/sysconfig-returns-incorrect-paths
  75. # for more information.
  76. if platform.python_implementation().lower() == "pypy":
  77. site_packages = distutils_sysconfig.get_python_lib()
  78. try:
  79. # Use getusersitepackages if this is present, as it ensures that the
  80. # value is initialised properly.
  81. user_site = site.getusersitepackages()
  82. except AttributeError:
  83. user_site = site.USER_SITE
  84. user_dir = expanduser('~')
  85. if WINDOWS:
  86. bin_py = os.path.join(sys.prefix, 'Scripts')
  87. bin_user = os.path.join(user_site, 'Scripts')
  88. # buildout uses 'bin' on Windows too?
  89. if not os.path.exists(bin_py):
  90. bin_py = os.path.join(sys.prefix, 'bin')
  91. bin_user = os.path.join(user_site, 'bin')
  92. config_basename = 'pip.ini'
  93. legacy_storage_dir = os.path.join(user_dir, 'pip')
  94. legacy_config_file = os.path.join(
  95. legacy_storage_dir,
  96. config_basename,
  97. )
  98. else:
  99. bin_py = os.path.join(sys.prefix, 'bin')
  100. bin_user = os.path.join(user_site, 'bin')
  101. config_basename = 'pip.conf'
  102. legacy_storage_dir = os.path.join(user_dir, '.pip')
  103. legacy_config_file = os.path.join(
  104. legacy_storage_dir,
  105. config_basename,
  106. )
  107. # Forcing to use /usr/local/bin for standard macOS framework installs
  108. # Also log to ~/Library/Logs/ for use with the Console.app log viewer
  109. if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/':
  110. bin_py = '/usr/local/bin'
  111. site_config_files = [
  112. os.path.join(path, config_basename)
  113. for path in appdirs.site_config_dirs('pip')
  114. ]
  115. venv_config_file = os.path.join(sys.prefix, config_basename)
  116. new_config_file = os.path.join(appdirs.user_config_dir("pip"), config_basename)
  117. def distutils_scheme(dist_name, user=False, home=None, root=None,
  118. isolated=False, prefix=None):
  119. # type:(str, bool, str, str, bool, str) -> dict
  120. """
  121. Return a distutils install scheme
  122. """
  123. from distutils.dist import Distribution
  124. scheme = {}
  125. if isolated:
  126. extra_dist_args = {"script_args": ["--no-user-cfg"]}
  127. else:
  128. extra_dist_args = {}
  129. dist_args = {'name': dist_name} # type: Dict[str, Union[str, List[str]]]
  130. dist_args.update(extra_dist_args)
  131. d = Distribution(dist_args)
  132. # Ignoring, typeshed issue reported python/typeshed/issues/2567
  133. d.parse_config_files()
  134. # NOTE: Ignoring type since mypy can't find attributes on 'Command'
  135. i = d.get_command_obj('install', create=True) # type: Any
  136. assert i is not None
  137. # NOTE: setting user or home has the side-effect of creating the home dir
  138. # or user base for installations during finalize_options()
  139. # ideally, we'd prefer a scheme class that has no side-effects.
  140. assert not (user and prefix), "user={} prefix={}".format(user, prefix)
  141. i.user = user or i.user
  142. if user:
  143. i.prefix = ""
  144. i.prefix = prefix or i.prefix
  145. i.home = home or i.home
  146. i.root = root or i.root
  147. i.finalize_options()
  148. for key in SCHEME_KEYS:
  149. scheme[key] = getattr(i, 'install_' + key)
  150. # install_lib specified in setup.cfg should install *everything*
  151. # into there (i.e. it takes precedence over both purelib and
  152. # platlib). Note, i.install_lib is *always* set after
  153. # finalize_options(); we only want to override here if the user
  154. # has explicitly requested it hence going back to the config
  155. # Ignoring, typeshed issue reported python/typeshed/issues/2567
  156. if 'install_lib' in d.get_option_dict('install'): # type: ignore
  157. scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib))
  158. if running_under_virtualenv():
  159. scheme['headers'] = os.path.join(
  160. sys.prefix,
  161. 'include',
  162. 'site',
  163. 'python' + sys.version[:3],
  164. dist_name,
  165. )
  166. if root is not None:
  167. path_no_drive = os.path.splitdrive(
  168. os.path.abspath(scheme["headers"]))[1]
  169. scheme["headers"] = os.path.join(
  170. root,
  171. path_no_drive[1:],
  172. )
  173. return scheme