legacy.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. """Legacy installation process, i.e. `setup.py install`.
  2. """
  3. import logging
  4. import os
  5. import sys
  6. from distutils.util import change_root
  7. from typing import List, Optional, Sequence
  8. from pip._internal.build_env import BuildEnvironment
  9. from pip._internal.exceptions import InstallationError
  10. from pip._internal.models.scheme import Scheme
  11. from pip._internal.utils.logging import indent_log
  12. from pip._internal.utils.misc import ensure_dir
  13. from pip._internal.utils.setuptools_build import make_setuptools_install_args
  14. from pip._internal.utils.subprocess import runner_with_spinner_message
  15. from pip._internal.utils.temp_dir import TempDirectory
  16. logger = logging.getLogger(__name__)
  17. class LegacyInstallFailure(Exception):
  18. def __init__(self):
  19. # type: () -> None
  20. self.parent = sys.exc_info()
  21. def install(
  22. install_options, # type: List[str]
  23. global_options, # type: Sequence[str]
  24. root, # type: Optional[str]
  25. home, # type: Optional[str]
  26. prefix, # type: Optional[str]
  27. use_user_site, # type: bool
  28. pycompile, # type: bool
  29. scheme, # type: Scheme
  30. setup_py_path, # type: str
  31. isolated, # type: bool
  32. req_name, # type: str
  33. build_env, # type: BuildEnvironment
  34. unpacked_source_directory, # type: str
  35. req_description, # type: str
  36. ):
  37. # type: (...) -> bool
  38. header_dir = scheme.headers
  39. with TempDirectory(kind="record") as temp_dir:
  40. try:
  41. record_filename = os.path.join(temp_dir.path, 'install-record.txt')
  42. install_args = make_setuptools_install_args(
  43. setup_py_path,
  44. global_options=global_options,
  45. install_options=install_options,
  46. record_filename=record_filename,
  47. root=root,
  48. prefix=prefix,
  49. header_dir=header_dir,
  50. home=home,
  51. use_user_site=use_user_site,
  52. no_user_config=isolated,
  53. pycompile=pycompile,
  54. )
  55. runner = runner_with_spinner_message(
  56. f"Running setup.py install for {req_name}"
  57. )
  58. with indent_log(), build_env:
  59. runner(
  60. cmd=install_args,
  61. cwd=unpacked_source_directory,
  62. )
  63. if not os.path.exists(record_filename):
  64. logger.debug('Record file %s not found', record_filename)
  65. # Signal to the caller that we didn't install the new package
  66. return False
  67. except Exception:
  68. # Signal to the caller that we didn't install the new package
  69. raise LegacyInstallFailure
  70. # At this point, we have successfully installed the requirement.
  71. # We intentionally do not use any encoding to read the file because
  72. # setuptools writes the file using distutils.file_util.write_file,
  73. # which does not specify an encoding.
  74. with open(record_filename) as f:
  75. record_lines = f.read().splitlines()
  76. def prepend_root(path):
  77. # type: (str) -> str
  78. if root is None or not os.path.isabs(path):
  79. return path
  80. else:
  81. return change_root(root, path)
  82. for line in record_lines:
  83. directory = os.path.dirname(line)
  84. if directory.endswith('.egg-info'):
  85. egg_info_dir = prepend_root(directory)
  86. break
  87. else:
  88. message = (
  89. "{} did not indicate that it installed an "
  90. ".egg-info directory. Only setup.py projects "
  91. "generating .egg-info directories are supported."
  92. ).format(req_description)
  93. raise InstallationError(message)
  94. new_lines = []
  95. for line in record_lines:
  96. filename = line.strip()
  97. if os.path.isdir(filename):
  98. filename += os.path.sep
  99. new_lines.append(
  100. os.path.relpath(prepend_root(filename), egg_info_dir)
  101. )
  102. new_lines.sort()
  103. ensure_dir(egg_info_dir)
  104. inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt')
  105. with open(inst_files_path, 'w') as f:
  106. f.write('\n'.join(new_lines) + '\n')
  107. return True