locations.py 6.2 KB

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