locations.py 5.7 KB

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