[meld] Bzr updates (bgo#701970)
- From: Kai Willadsen <kaiw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [meld] Bzr updates (bgo#701970)
- Date: Sat, 24 May 2014 20:52:36 +0000 (UTC)
commit 0ba45fa930770499bd12f88a01f0d9afb37ceb7d
Author: Louis des Landes <louis psykar com>
Date: Tue May 20 00:09:49 2014 +1000
Bzr updates (bgo#701970)
meld/vc/bzr.py | 106 +++++++++++++++++++++++++++++++++++++++++++++----------
test/testbzr.sh | 4 ++
2 files changed, 91 insertions(+), 19 deletions(-)
---
diff --git a/meld/vc/bzr.py b/meld/vc/bzr.py
index 17efbfc..294a4ea 100644
--- a/meld/vc/bzr.py
+++ b/meld/vc/bzr.py
@@ -1,3 +1,4 @@
+# coding=utf-8
### Copyright (C) 2002-2005 Stephen Kennedy <stevek gnome org>
### Copyright (C) 2005 Aaron Bentley <aaron bentley utoronto ca>
@@ -21,6 +22,7 @@
### THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
### (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
### THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+from collections import defaultdict
import errno
import os
@@ -38,12 +40,18 @@ class Vc(_vc.CachedVc):
CMDARGS = ["--no-aliases", "--no-plugins"]
NAME = "Bazaar"
VC_DIR = ".bzr"
+ PATCH_INDEX_RE = "^=== modified file '(.*)' (.*)$"
CONFLICT_RE = "conflict in (.*)$"
+ #RENAMED_RE = u"^(.*) ⇒ (.*)$"
+ RENAMED_RE = u"^(.*) => (.*)$"
+
commit_statuses = (
- _vc.STATE_MODIFIED, _vc.STATE_NEW, _vc.STATE_REMOVED
+ _vc.STATE_MODIFIED, _vc.STATE_RENAMED, _vc.STATE_NEW, _vc.STATE_REMOVED
)
+ VC_COLUMNS = (_vc.DATA_NAME, _vc.DATA_STATE, _vc.DATA_OPTIONS)
+
conflict_map = {
_vc.CONFLICT_BASE: '.BASE',
_vc.CONFLICT_OTHER: '.OTHER',
@@ -56,7 +64,7 @@ class Vc(_vc.CachedVc):
" ": None, # First status column empty
"+": None, # File versioned
"-": None, # File unversioned
- "R": None, # File renamed
+ "R": _vc.STATE_RENAMED, # File renamed
"?": _vc.STATE_NONE, # File unknown
"X": None, # File nonexistent (and unknown to bzr)
"C": _vc.STATE_CONFLICT, # File has conflicts
@@ -71,8 +79,21 @@ class Vc(_vc.CachedVc):
"M": _vc.STATE_MODIFIED, # File modified
}
- valid_status_re = r'[%s][%s][\*\s]\s*' % (''.join(state_1_map.keys()),
- ''.join(state_2_map.keys()))
+ state_3_map = {
+ " ": None,
+ "*": _vc.STATE_MODIFIED,
+ "/": _vc.STATE_MODIFIED,
+ "@": _vc.STATE_MODIFIED,
+ }
+
+ valid_status_re = r'[%s][%s][%s]\s*' % (''.join(state_1_map.keys()),
+ ''.join(state_2_map.keys()),
+ ''.join(state_3_map.keys()),)
+
+ def __init__(self, location):
+ super(Vc, self).__init__(location)
+ self._tree_cache = {}
+ self._tree_meta_cache = {}
def commit_command(self, message):
return [self.CMD] + self.CMDARGS + ["commit", "-m", message]
@@ -130,6 +151,7 @@ class Vc(_vc.CachedVc):
def _lookup_tree_cache(self, rootdir):
branch_root = _vc.popen(
[self.CMD] + self.CMDARGS + ["root", rootdir]).read().rstrip('\n')
+ entries = []
while 1:
try:
proc = _vc.popen([self.CMD] + self.CMDARGS +
@@ -140,25 +162,65 @@ class Vc(_vc.CachedVc):
if e.errno != errno.EAGAIN:
raise
- tree_state = {}
+ self._tree_cache = tree_cache = defaultdict(set)
+ self._tree_meta_cache = tree_meta_cache = defaultdict(list)
+ self._rename_cache = rename_cache = {}
+ self._reverse_rename_cache = {}
+ # Files can appear twice in the list if they conflict and were renamed
+ # at once.
for entry in entries:
+ meta = []
+ old_name = None
state_string, name = entry[:3], entry[4:].strip()
if not re.match(self.valid_status_re, state_string):
continue
- # TODO: We don't do anything with exec bit changes.
- state = self.state_1_map.get(state_string[0], None)
- if state is None:
- state = self.state_2_map.get(state_string[1], _vc.STATE_NORMAL)
- elif state == _vc.STATE_CONFLICT:
+
+ state1 = self.state_1_map.get(state_string[0])
+ state2 = self.state_2_map.get(state_string[1])
+ state3 = self.state_3_map.get(state_string[2])
+
+ states = {state1, state2, state3}
+
+ if _vc.STATE_CONFLICT in states:
real_path_match = re.search(self.CONFLICT_RE, name)
- if real_path_match is None:
- continue
- name = real_path_match.group(1)
+ if real_path_match is not None:
+ name = real_path_match.group(1)
+
+ if _vc.STATE_RENAMED in states:
+ real_path_match = re.search(self.RENAMED_RE, name)
+ if real_path_match is not None:
+ meta.append(name)
+ old_name = real_path_match.group(1)
+ name = real_path_match.group(2)
path = os.path.join(branch_root, name)
- tree_state[path] = state
+ if old_name:
+ old_path = os.path.join(branch_root, old_name)
+ rename_cache[old_path] = path
+
+ if state3 and state3 is _vc.STATE_MODIFIED:
+ # line = _vc.popen(self.diff_command() + [path]).readline()
+ line = _vc.popen(['bzr', 'diff', path]).readline()
+ executable_match = re.search(self.PATCH_INDEX_RE, line)
+ if executable_match:
+ meta.append(executable_match.group(2))
+
+
+
+ tree_cache[path].update(states)
+ tree_meta_cache[path].extend(meta)
+
+ # Handle any renames now
+ for old, new in rename_cache.items():
+ if old in tree_cache:
+ tree_cache[new].update(tree_cache[old])
+ tree_meta_cache[new].extend(tree_meta_cache[old])
+ del tree_cache[old]
+ del tree_meta_cache[old]
+ self._reverse_rename_cache[new] = old
- return tree_state
+ tree_cache = dict((x, max(y)) for x,y in tree_cache.items())
+ return tree_cache
def _get_dirsandfiles(self, directory, dirs, files):
tree = self._get_tree_cache(directory)
@@ -172,19 +234,22 @@ class Vc(_vc.CachedVc):
mydir, name = os.path.split(mydir)
if mydir != directory:
continue
+ meta = ','.join(self._tree_meta_cache.get(path, []))
if path.endswith('/'):
- retdirs.append(_vc.Dir(path[:-1], name, state))
+ retdirs.append(_vc.Dir(path[:-1], name, state, options=meta))
else:
- retfiles.append(_vc.File(path, name, state))
+ retfiles.append(_vc.File(path, name, state, options=meta))
bzrfiles[name] = 1
for f, path in files:
if f not in bzrfiles:
state = _vc.STATE_NORMAL
- retfiles.append(_vc.File(path, f, state))
+ meta = ','.join(self._tree_meta_cache.get(path, []))
+ retfiles.append(_vc.File(path, f, state, options=meta))
for d, path in dirs:
if d not in bzrfiles:
state = _vc.STATE_NORMAL
- retdirs.append(_vc.Dir(path, d, state))
+ meta = ','.join(self._tree_meta_cache.get(path, []))
+ retdirs.append(_vc.Dir(path, d, state, options=meta))
return retdirs, retfiles
def get_path_for_repo_file(self, path, commit=None):
@@ -210,6 +275,9 @@ class Vc(_vc.CachedVc):
return f.name
def get_path_for_conflict(self, path, conflict):
+ if path in self._reverse_rename_cache and not \
+ conflict == _vc.CONFLICT_MERGED:
+ path = self._reverse_rename_cache[path]
if not path.startswith(self.root + os.path.sep):
raise _vc.InvalidVCPath(self, path, "Path not in repository")
diff --git a/test/testbzr.sh b/test/testbzr.sh
index dbe62e3..3fc407b 100755
--- a/test/testbzr.sh
+++ b/test/testbzr.sh
@@ -10,6 +10,7 @@ echo "modified" > modified.txt
echo "deleted" > deleted.txt
echo "exec" > exec.txt
echo "conflict" > conflict.txt
+echo "conflict2" > conflict2.txt
mkdir normal-dir
mkdir renamed-dir
@@ -29,11 +30,13 @@ bzr branch bzrtest1 bzrtest2
# Make a change back in the original branch so we get a conflict
cd bzrtest1
echo "parent change" >> conflict.txt
+echo "parent change" >> conflict2.txt
bzr commit -m "Parent change"
# CD back to the new branch and make a change
cd ../bzrtest2
echo "child change" >> conflict.txt
+echo "child change" >> conflict2.txt
bzr commit -m "Child change"
bzr merge
@@ -69,3 +72,4 @@ chmod +x ./exec.txt
# Can't check this... if we -x on owner bzr can't status it anyway.
chmod g-x ./exec-dir
+bzr mv ./conflict2.txt ./conflict2-moved.txt
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]