PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/meld/vc/mercurial.py

https://bitbucket.org/eddieh/meld
Python | 138 lines | 109 code | 8 blank | 21 comment | 5 complexity | 6e55a89b26e0ba9f7f7772d45affb278 MD5 | raw file
  1. ### Copyright (C) 2002-2005 Stephen Kennedy <stevek@gnome.org>
  2. ### Redistribution and use in source and binary forms, with or without
  3. ### modification, are permitted provided that the following conditions
  4. ### are met:
  5. ###
  6. ### 1. Redistributions of source code must retain the above copyright
  7. ### notice, this list of conditions and the following disclaimer.
  8. ### 2. Redistributions in binary form must reproduce the above copyright
  9. ### notice, this list of conditions and the following disclaimer in the
  10. ### documentation and/or other materials provided with the distribution.
  11. ### THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  12. ### IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  13. ### OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  14. ### IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  15. ### INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  16. ### NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  17. ### DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  18. ### THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  19. ### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  20. ### THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21. import errno
  22. import os
  23. from . import _vc
  24. class Vc(_vc.CachedVc):
  25. CMD = "hg"
  26. NAME = "Mercurial"
  27. VC_DIR = ".hg"
  28. PATCH_STRIP_NUM = 1
  29. # Mercurial diffs can be run in "git" mode
  30. PATCH_INDEX_RE = "^diff (?:-r \w+ |--git a/.* b/)(.*)$"
  31. DIFF_GIT_MODE = False
  32. state_map = {
  33. "?": _vc.STATE_NONE,
  34. "A": _vc.STATE_NEW,
  35. "C": _vc.STATE_NORMAL,
  36. "!": _vc.STATE_MISSING,
  37. "I": _vc.STATE_IGNORED,
  38. "M": _vc.STATE_MODIFIED,
  39. "R": _vc.STATE_REMOVED,
  40. }
  41. def commit_command(self, message):
  42. return [self.CMD,"commit","-m",message]
  43. def diff_command(self):
  44. ret = [self.CMD,"diff"]
  45. if self.DIFF_GIT_MODE:
  46. ret.append("--git")
  47. return ret
  48. def update_command(self):
  49. return [self.CMD,"update"]
  50. def add_command(self):
  51. return [self.CMD,"add"]
  52. def remove_command(self, force=0):
  53. return [self.CMD,"rm"]
  54. def revert_command(self):
  55. return [self.CMD,"revert"]
  56. def valid_repo(self):
  57. if _vc.call([self.CMD, "root"], cwd=self.root):
  58. return False
  59. else:
  60. return True
  61. def get_working_directory(self, workdir):
  62. if workdir.startswith("/"):
  63. return self.root
  64. else:
  65. return ''
  66. def _update_tree_state_cache(self, path, tree_state):
  67. """ Update the state of the file(s) at tree_state['path'] """
  68. while 1:
  69. try:
  70. # Get the status of modified files
  71. proc = _vc.popen([self.CMD, "status", '-A', path],
  72. cwd=self.location)
  73. entries = proc.read().split("\n")[:-1]
  74. # The following command removes duplicate file entries.
  75. # Just in case.
  76. entries = list(set(entries))
  77. break
  78. except OSError as e:
  79. if e.errno != errno.EAGAIN:
  80. raise
  81. if len(entries) == 0 and os.path.isfile(path):
  82. # If we're just updating a single file there's a chance that it
  83. # was it was previously modified, and now has been edited
  84. # so that it is un-modified. This will result in an empty
  85. # 'entries' list, and tree_state['path'] will still contain stale
  86. # data. When this corner case occurs we force tree_state['path']
  87. # to STATE_NORMAL.
  88. tree_state[path] = _vc.STATE_NORMAL
  89. else:
  90. # There are 1 or more modified files, parse their state
  91. for entry in entries:
  92. # we might have a space in file name, it should be ignored
  93. statekey, name = entry.split(" ", 1)
  94. path = os.path.join(self.location, name.strip())
  95. state = self.state_map.get(statekey.strip(), _vc.STATE_NONE)
  96. tree_state[path] = state
  97. def _lookup_tree_cache(self, rootdir):
  98. # Get a list of all files in rootdir, as well as their status
  99. tree_state = {}
  100. self._update_tree_state_cache("./", tree_state)
  101. return tree_state
  102. def update_file_state(self, path):
  103. tree_state = self._get_tree_cache(os.path.dirname(path))
  104. self._update_tree_state_cache(path, tree_state)
  105. def _get_dirsandfiles(self, directory, dirs, files):
  106. tree = self._get_tree_cache(directory)
  107. retfiles = []
  108. retdirs = []
  109. for name, path in files:
  110. state = tree.get(path, _vc.STATE_NORMAL)
  111. retfiles.append(_vc.File(path, name, state))
  112. for name, path in dirs:
  113. # mercurial does not operate on dirs, just files
  114. retdirs.append(_vc.Dir(path, name, _vc.STATE_NORMAL))
  115. for path, state in tree.items():
  116. # removed files are not in the filesystem, so must be added here
  117. if state in (_vc.STATE_REMOVED, _vc.STATE_MISSING):
  118. folder, name = os.path.split(path)
  119. if folder == directory:
  120. retfiles.append(_vc.File(path, name, state))
  121. return retdirs, retfiles