mercurial.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import os
  2. import tempfile
  3. import re
  4. import sys
  5. from pip.util import call_subprocess
  6. from pip.util import display_path, rmtree
  7. from pip.log import logger
  8. from pip.vcs import vcs, VersionControl
  9. from pip.download import path_to_url
  10. from pip.backwardcompat import ConfigParser
  11. class Mercurial(VersionControl):
  12. name = 'hg'
  13. dirname = '.hg'
  14. repo_name = 'clone'
  15. schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http')
  16. bundle_file = 'hg-clone.txt'
  17. guide = ('# This was a Mercurial repo; to make it a repo again run:\n'
  18. 'hg init\nhg pull %(url)s\nhg update -r %(rev)s\n')
  19. def parse_vcs_bundle_file(self, content):
  20. url = rev = None
  21. for line in content.splitlines():
  22. if not line.strip() or line.strip().startswith('#'):
  23. continue
  24. url_match = re.search(r'hg\s*pull\s*(.*)\s*', line)
  25. if url_match:
  26. url = url_match.group(1).strip()
  27. rev_match = re.search(r'^hg\s*update\s*-r\s*(.*)\s*', line)
  28. if rev_match:
  29. rev = rev_match.group(1).strip()
  30. if url and rev:
  31. return url, rev
  32. return None, None
  33. def export(self, location):
  34. """Export the Hg repository at the url to the destination location"""
  35. temp_dir = tempfile.mkdtemp('-export', 'pip-')
  36. self.unpack(temp_dir)
  37. try:
  38. call_subprocess(
  39. [self.cmd, 'archive', location],
  40. filter_stdout=self._filter, show_stdout=False, cwd=temp_dir)
  41. finally:
  42. rmtree(temp_dir)
  43. def switch(self, dest, url, rev_options):
  44. repo_config = os.path.join(dest, self.dirname, 'hgrc')
  45. config = ConfigParser.SafeConfigParser()
  46. try:
  47. config.read(repo_config)
  48. config.set('paths', 'default', url)
  49. config_file = open(repo_config, 'w')
  50. config.write(config_file)
  51. config_file.close()
  52. except (OSError, ConfigParser.NoSectionError):
  53. e = sys.exc_info()[1]
  54. logger.warn(
  55. 'Could not switch Mercurial repository to %s: %s'
  56. % (url, e))
  57. else:
  58. call_subprocess([self.cmd, 'update', '-q'] + rev_options, cwd=dest)
  59. def update(self, dest, rev_options):
  60. call_subprocess([self.cmd, 'pull', '-q'], cwd=dest)
  61. call_subprocess(
  62. [self.cmd, 'update', '-q'] + rev_options, cwd=dest)
  63. def obtain(self, dest):
  64. url, rev = self.get_url_rev()
  65. if rev:
  66. rev_options = [rev]
  67. rev_display = ' (to revision %s)' % rev
  68. else:
  69. rev_options = []
  70. rev_display = ''
  71. if self.check_destination(dest, url, rev_options, rev_display):
  72. logger.notify('Cloning hg %s%s to %s'
  73. % (url, rev_display, display_path(dest)))
  74. call_subprocess([self.cmd, 'clone', '--noupdate', '-q', url, dest])
  75. call_subprocess([self.cmd, 'update', '-q'] + rev_options, cwd=dest)
  76. def get_url(self, location):
  77. url = call_subprocess(
  78. [self.cmd, 'showconfig', 'paths.default'],
  79. show_stdout=False, cwd=location).strip()
  80. if self._is_local_repository(url):
  81. url = path_to_url(url)
  82. return url.strip()
  83. def get_tag_revs(self, location):
  84. tags = call_subprocess(
  85. [self.cmd, 'tags'], show_stdout=False, cwd=location)
  86. tag_revs = []
  87. for line in tags.splitlines():
  88. tags_match = re.search(r'([\w\d\.-]+)\s*([\d]+):.*$', line)
  89. if tags_match:
  90. tag = tags_match.group(1)
  91. rev = tags_match.group(2)
  92. if "tip" != tag:
  93. tag_revs.append((rev.strip(), tag.strip()))
  94. return dict(tag_revs)
  95. def get_branch_revs(self, location):
  96. branches = call_subprocess(
  97. [self.cmd, 'branches'], show_stdout=False, cwd=location)
  98. branch_revs = []
  99. for line in branches.splitlines():
  100. branches_match = re.search(r'([\w\d\.-]+)\s*([\d]+):.*$', line)
  101. if branches_match:
  102. branch = branches_match.group(1)
  103. rev = branches_match.group(2)
  104. if "default" != branch:
  105. branch_revs.append((rev.strip(), branch.strip()))
  106. return dict(branch_revs)
  107. def get_revision(self, location):
  108. current_revision = call_subprocess(
  109. [self.cmd, 'parents', '--template={rev}'],
  110. show_stdout=False, cwd=location).strip()
  111. return current_revision
  112. def get_revision_hash(self, location):
  113. current_rev_hash = call_subprocess(
  114. [self.cmd, 'parents', '--template={node}'],
  115. show_stdout=False, cwd=location).strip()
  116. return current_rev_hash
  117. def get_src_requirement(self, dist, location, find_tags):
  118. repo = self.get_url(location)
  119. if not repo.lower().startswith('hg:'):
  120. repo = 'hg+' + repo
  121. egg_project_name = dist.egg_name().split('-', 1)[0]
  122. if not repo:
  123. return None
  124. current_rev = self.get_revision(location)
  125. current_rev_hash = self.get_revision_hash(location)
  126. tag_revs = self.get_tag_revs(location)
  127. branch_revs = self.get_branch_revs(location)
  128. if current_rev in tag_revs:
  129. # It's a tag
  130. full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev])
  131. elif current_rev in branch_revs:
  132. # It's the tip of a branch
  133. full_egg_name = '%s-%s' % (egg_project_name, branch_revs[current_rev])
  134. else:
  135. full_egg_name = '%s-dev' % egg_project_name
  136. return '%s@%s#egg=%s' % (repo, current_rev_hash, full_egg_name)
  137. vcs.register(Mercurial)