mercurial.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import configparser
  2. import logging
  3. import os
  4. from typing import List, Optional, Tuple
  5. from pip._internal.exceptions import BadCommand, InstallationError
  6. from pip._internal.utils.misc import HiddenText, display_path
  7. from pip._internal.utils.subprocess import make_command
  8. from pip._internal.utils.urls import path_to_url
  9. from pip._internal.vcs.versioncontrol import (
  10. RevOptions,
  11. VersionControl,
  12. find_path_to_project_root_from_repo_root,
  13. vcs,
  14. )
  15. logger = logging.getLogger(__name__)
  16. class Mercurial(VersionControl):
  17. name = "hg"
  18. dirname = ".hg"
  19. repo_name = "clone"
  20. schemes = (
  21. "hg+file",
  22. "hg+http",
  23. "hg+https",
  24. "hg+ssh",
  25. "hg+static-http",
  26. )
  27. @staticmethod
  28. def get_base_rev_args(rev: str) -> List[str]:
  29. return [rev]
  30. def fetch_new(
  31. self, dest: str, url: HiddenText, rev_options: RevOptions, verbosity: int
  32. ) -> None:
  33. rev_display = rev_options.to_display()
  34. logger.info(
  35. "Cloning hg %s%s to %s",
  36. url,
  37. rev_display,
  38. display_path(dest),
  39. )
  40. if verbosity <= 0:
  41. flags: Tuple[str, ...] = ("--quiet",)
  42. elif verbosity == 1:
  43. flags = ()
  44. elif verbosity == 2:
  45. flags = ("--verbose",)
  46. else:
  47. flags = ("--verbose", "--debug")
  48. self.run_command(make_command("clone", "--noupdate", *flags, url, dest))
  49. self.run_command(
  50. make_command("update", *flags, rev_options.to_args()),
  51. cwd=dest,
  52. )
  53. def switch(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None:
  54. repo_config = os.path.join(dest, self.dirname, "hgrc")
  55. config = configparser.RawConfigParser()
  56. try:
  57. config.read(repo_config)
  58. config.set("paths", "default", url.secret)
  59. with open(repo_config, "w") as config_file:
  60. config.write(config_file)
  61. except (OSError, configparser.NoSectionError) as exc:
  62. logger.warning("Could not switch Mercurial repository to %s: %s", url, exc)
  63. else:
  64. cmd_args = make_command("update", "-q", rev_options.to_args())
  65. self.run_command(cmd_args, cwd=dest)
  66. def update(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None:
  67. self.run_command(["pull", "-q"], cwd=dest)
  68. cmd_args = make_command("update", "-q", rev_options.to_args())
  69. self.run_command(cmd_args, cwd=dest)
  70. @classmethod
  71. def get_remote_url(cls, location: str) -> str:
  72. url = cls.run_command(
  73. ["showconfig", "paths.default"],
  74. show_stdout=False,
  75. stdout_only=True,
  76. cwd=location,
  77. ).strip()
  78. if cls._is_local_repository(url):
  79. url = path_to_url(url)
  80. return url.strip()
  81. @classmethod
  82. def get_revision(cls, location: str) -> str:
  83. """
  84. Return the repository-local changeset revision number, as an integer.
  85. """
  86. current_revision = cls.run_command(
  87. ["parents", "--template={rev}"],
  88. show_stdout=False,
  89. stdout_only=True,
  90. cwd=location,
  91. ).strip()
  92. return current_revision
  93. @classmethod
  94. def get_requirement_revision(cls, location: str) -> str:
  95. """
  96. Return the changeset identification hash, as a 40-character
  97. hexadecimal string
  98. """
  99. current_rev_hash = cls.run_command(
  100. ["parents", "--template={node}"],
  101. show_stdout=False,
  102. stdout_only=True,
  103. cwd=location,
  104. ).strip()
  105. return current_rev_hash
  106. @classmethod
  107. def is_commit_id_equal(cls, dest: str, name: Optional[str]) -> bool:
  108. """Always assume the versions don't match"""
  109. return False
  110. @classmethod
  111. def get_subdirectory(cls, location: str) -> Optional[str]:
  112. """
  113. Return the path to Python project root, relative to the repo root.
  114. Return None if the project root is in the repo root.
  115. """
  116. # find the repo root
  117. repo_root = cls.run_command(
  118. ["root"], show_stdout=False, stdout_only=True, cwd=location
  119. ).strip()
  120. if not os.path.isabs(repo_root):
  121. repo_root = os.path.abspath(os.path.join(location, repo_root))
  122. return find_path_to_project_root_from_repo_root(location, repo_root)
  123. @classmethod
  124. def get_repository_root(cls, location: str) -> Optional[str]:
  125. loc = super().get_repository_root(location)
  126. if loc:
  127. return loc
  128. try:
  129. r = cls.run_command(
  130. ["root"],
  131. cwd=location,
  132. show_stdout=False,
  133. stdout_only=True,
  134. on_returncode="raise",
  135. log_failed_cmd=False,
  136. )
  137. except BadCommand:
  138. logger.debug(
  139. "could not determine if %s is under hg control "
  140. "because hg is not available",
  141. location,
  142. )
  143. return None
  144. except InstallationError:
  145. return None
  146. return os.path.normpath(r.rstrip("\r\n"))
  147. vcs.register(Mercurial)