locations.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. """Locations where we look for configs, install stuff, etc"""
  2. import sys
  3. import site
  4. import os
  5. import tempfile
  6. from distutils.command.install import install, SCHEME_KEYS
  7. import getpass
  8. from pip.backwardcompat import get_python_lib, get_path_uid, user_site
  9. import pip.exceptions
  10. DELETE_MARKER_MESSAGE = '''\
  11. This file is placed here by pip to indicate the source was put
  12. here by pip.
  13. Once this package is successfully installed this source code will be
  14. deleted (unless you remove this file).
  15. '''
  16. PIP_DELETE_MARKER_FILENAME = 'pip-delete-this-directory.txt'
  17. def write_delete_marker_file(directory):
  18. """
  19. Write the pip delete marker file into this directory.
  20. """
  21. filepath = os.path.join(directory, PIP_DELETE_MARKER_FILENAME)
  22. marker_fp = open(filepath, 'w')
  23. marker_fp.write(DELETE_MARKER_MESSAGE)
  24. marker_fp.close()
  25. def running_under_virtualenv():
  26. """
  27. Return True if we're running inside a virtualenv, False otherwise.
  28. """
  29. if hasattr(sys, 'real_prefix'):
  30. return True
  31. elif sys.prefix != getattr(sys, "base_prefix", sys.prefix):
  32. return True
  33. return False
  34. def virtualenv_no_global():
  35. """
  36. Return True if in a venv and no system site packages.
  37. """
  38. #this mirrors the logic in virtualenv.py for locating the no-global-site-packages.txt file
  39. site_mod_dir = os.path.dirname(os.path.abspath(site.__file__))
  40. no_global_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt')
  41. if running_under_virtualenv() and os.path.isfile(no_global_file):
  42. return True
  43. def __get_username():
  44. """ Returns the effective username of the current process. """
  45. if sys.platform == 'win32':
  46. return getpass.getuser()
  47. import pwd
  48. return pwd.getpwuid(os.geteuid()).pw_name
  49. def _get_build_prefix():
  50. """ Returns a safe build_prefix """
  51. path = os.path.join(tempfile.gettempdir(), 'pip_build_%s' %
  52. __get_username())
  53. if sys.platform == 'win32':
  54. """ on windows(tested on 7) temp dirs are isolated """
  55. return path
  56. try:
  57. os.mkdir(path)
  58. write_delete_marker_file(path)
  59. except OSError:
  60. file_uid = None
  61. try:
  62. # raises OSError for symlinks
  63. # https://github.com/pypa/pip/pull/935#discussion_r5307003
  64. file_uid = get_path_uid(path)
  65. except OSError:
  66. file_uid = None
  67. if file_uid != os.geteuid():
  68. msg = "The temporary folder for building (%s) is either not owned by you, or is a symlink." \
  69. % path
  70. print (msg)
  71. print("pip will not work until the temporary folder is " + \
  72. "either deleted or is a real directory owned by your user account.")
  73. raise pip.exceptions.InstallationError(msg)
  74. return path
  75. if running_under_virtualenv():
  76. build_prefix = os.path.join(sys.prefix, 'build')
  77. src_prefix = os.path.join(sys.prefix, 'src')
  78. else:
  79. # Note: intentionally NOT using mkdtemp
  80. # See https://github.com/pypa/pip/issues/906 for plan to move to mkdtemp
  81. build_prefix = _get_build_prefix()
  82. ## FIXME: keep src in cwd for now (it is not a temporary folder)
  83. try:
  84. src_prefix = os.path.join(os.getcwd(), 'src')
  85. except OSError:
  86. # In case the current working directory has been renamed or deleted
  87. sys.exit("The folder you are executing pip from can no longer be found.")
  88. # under Mac OS X + virtualenv sys.prefix is not properly resolved
  89. # it is something like /path/to/python/bin/..
  90. # Note: using realpath due to tmp dirs on OSX being symlinks
  91. build_prefix = os.path.abspath(os.path.realpath(build_prefix))
  92. src_prefix = os.path.abspath(src_prefix)
  93. # FIXME doesn't account for venv linked to global site-packages
  94. site_packages = get_python_lib()
  95. user_dir = os.path.expanduser('~')
  96. if sys.platform == 'win32':
  97. bin_py = os.path.join(sys.prefix, 'Scripts')
  98. bin_user = os.path.join(user_site, 'Scripts') if user_site else None
  99. # buildout uses 'bin' on Windows too?
  100. if not os.path.exists(bin_py):
  101. bin_py = os.path.join(sys.prefix, 'bin')
  102. bin_user = os.path.join(user_site, 'bin') if user_site else None
  103. default_storage_dir = os.path.join(user_dir, 'pip')
  104. default_config_file = os.path.join(default_storage_dir, 'pip.ini')
  105. default_log_file = os.path.join(default_storage_dir, 'pip.log')
  106. else:
  107. bin_py = os.path.join(sys.prefix, 'bin')
  108. bin_user = os.path.join(user_site, 'bin') if user_site else None
  109. default_storage_dir = os.path.join(user_dir, '.pip')
  110. default_config_file = os.path.join(default_storage_dir, 'pip.conf')
  111. default_log_file = os.path.join(default_storage_dir, 'pip.log')
  112. # Forcing to use /usr/local/bin for standard Mac OS X framework installs
  113. # Also log to ~/Library/Logs/ for use with the Console.app log viewer
  114. if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/':
  115. bin_py = '/usr/local/bin'
  116. default_log_file = os.path.join(user_dir, 'Library/Logs/pip.log')
  117. def distutils_scheme(dist_name, user=False, home=None, root=None):
  118. """
  119. Return a distutils install scheme
  120. """
  121. from distutils.dist import Distribution
  122. scheme = {}
  123. d = Distribution({'name': dist_name})
  124. d.parse_config_files()
  125. i = d.get_command_obj('install', create=True)
  126. # NOTE: setting user or home has the side-effect of creating the home dir or
  127. # user base for installations during finalize_options()
  128. # ideally, we'd prefer a scheme class that has no side-effects.
  129. i.user = user or i.user
  130. i.home = home or i.home
  131. i.root = root or i.root
  132. i.finalize_options()
  133. for key in SCHEME_KEYS:
  134. scheme[key] = getattr(i, 'install_'+key)
  135. if running_under_virtualenv():
  136. scheme['headers'] = os.path.join(sys.prefix,
  137. 'include',
  138. 'site',
  139. 'python' + sys.version[:3],
  140. dist_name)
  141. if root is not None:
  142. scheme["headers"] = os.path.join(
  143. root,
  144. os.path.abspath(scheme["headers"])[1:],
  145. )
  146. return scheme