Skip to content

Commit b2d3d92

Browse files
author
jomae
committed
1.0.14dev: fix IndexError raised from diff_tree() raised when git repository has a file started with a colon character (closes #12758)
git-svn-id: http://trac.edgewall.org/intertrac/log:/branches/1.0-stable@15759 af82e41b-90c4-0310-8c96-b1721e28e2e2
1 parent 7da7029 commit b2d3d92

File tree

3 files changed

+100
-36
lines changed

3 files changed

+100
-36
lines changed

tracopt/versioncontrol/git/PyGIT.py

+35-35
Original file line numberDiff line numberDiff line change
@@ -1011,44 +1011,44 @@ def diff_tree(self, tree1, tree2, path='', find_renames=False):
10111011
if find_renames:
10121012
diff_tree_args.append('-M')
10131013
diff_tree_args.extend([str(tree1) if tree1 else '--root',
1014-
str(tree2),
1015-
'--', path])
1014+
str(tree2), '--', path])
1015+
result = self.repo.diff_tree(*diff_tree_args)
1016+
if not result:
1017+
return
10161018

1017-
lines = self.repo.diff_tree(*diff_tree_args).split('\0')
1019+
def iter_entry(result):
1020+
start = 0
1021+
while True:
1022+
idx = result.find('\0', start)
1023+
if idx == -1:
1024+
return
1025+
yield result[start:idx]
1026+
start = idx + 1
1027+
1028+
iterate = iter_entry(result)
10181029

1019-
assert lines[-1] == ''
1020-
del lines[-1]
1030+
def next_entry():
1031+
return iterate.next()
10211032

1022-
if tree1 is None and lines:
1033+
if not tree1:
10231034
# if only one tree-sha is given on commandline,
10241035
# the first line is just the redundant tree-sha itself...
1025-
assert not lines[0].startswith(':')
1026-
del lines[0]
1027-
1028-
# FIXME: the following code is ugly, needs rewrite
1029-
1030-
chg = None
1031-
1032-
def __chg_tuple():
1033-
if len(chg) == 6:
1034-
chg.append(None)
1035-
else:
1036-
chg[6] = self._fs_to_unicode(chg[6])
1037-
chg[5] = self._fs_to_unicode(chg[5])
1036+
entry = next_entry()
1037+
assert not entry.startswith(':')
10381038

1039-
assert len(chg) == 7
1040-
return tuple(chg)
1041-
1042-
for line in lines:
1043-
if line.startswith(':'):
1044-
if chg:
1045-
yield __chg_tuple()
1046-
1047-
chg = line[1:].split()
1048-
assert len(chg) == 5
1049-
else:
1050-
chg.append(line)
1051-
1052-
# handle left-over chg entry
1053-
if chg:
1054-
yield __chg_tuple()
1039+
while True:
1040+
try:
1041+
entry = next_entry()
1042+
except StopIteration:
1043+
return
1044+
assert entry.startswith(':')
1045+
values = entry[1:].split(' ')
1046+
assert len(values) == 5
1047+
old_mode, new_mode, old_sha, new_sha, change = values
1048+
change = change[:1]
1049+
old_path = self._fs_to_unicode(next_entry())
1050+
new_path = None
1051+
if change in ('R', 'C'): # renamed or copied
1052+
new_path = self._fs_to_unicode(next_entry())
1053+
yield (old_mode, new_mode, old_sha, new_sha, change, old_path,
1054+
new_path)

tracopt/versioncontrol/git/git_fs.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ def get_changes(self):
872872
if mode2.startswith('04') or mode1.startswith('04') \
873873
else Node.FILE
874874

875-
action = GitChangeset.action_map[action[0]]
875+
action = GitChangeset.action_map[action]
876876

877877
if action == Changeset.ADD:
878878
p_path = p_rev = None

tracopt/versioncontrol/git/tests/git_fs.py

+64
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,70 @@ def test_iter_nodes(self):
778778
(root_commit, 'B/b2.txt'),
779779
], [(node.created_rev, node.path) for node in nodes])
780780

781+
def test_colon_character_in_filename(self):
782+
self._git_init(data=False)
783+
self._git_fast_import(self._data_colon_character_in_filename)
784+
self._add_repository('gitrepos')
785+
repos = self._repomgr.get_repository('gitrepos')
786+
repos.sync()
787+
rev1 = '382e1e6b85ba20ce8a84af1a875eaa50b8e1e092' # root commit
788+
rev2 = 'd8001832aad079f85a39a54a388a8b15fe31093d'
789+
ADD = Changeset.ADD
790+
MOVE = Changeset.MOVE
791+
FILE = Node.FILE
792+
793+
cset = repos.get_changeset(rev1)
794+
self.assertEqual(set([('0100644', FILE, ADD, None, None),
795+
('0100644.txt', FILE, ADD, None, None),
796+
(':100644', FILE, ADD, None, None),
797+
(':100644.txt', FILE, ADD, None, None),
798+
('a100644', FILE, ADD, None, None),
799+
('a100644.txt', FILE, ADD, None, None)
800+
]),
801+
set(cset.get_changes()))
802+
803+
cset = repos.get_changeset(rev2)
804+
self.assertEqual(set([(':100666', FILE, MOVE, ':100644', rev1)]),
805+
set(cset.get_changes()))
806+
807+
_data_colon_character_in_filename = """\
808+
blob
809+
mark :1
810+
data 0
811+
812+
blob
813+
mark :2
814+
data 16
815+
...............
816+
817+
reset refs/heads/master
818+
commit refs/heads/master
819+
mark :3
820+
author Joe <[email protected]> 1491387182 +0000
821+
committer Joe <[email protected]> 1491387182 +0000
822+
data 9
823+
(#12758)
824+
M 100644 :1 0100644.txt
825+
M 100644 :1 0100644
826+
M 100644 :1 :100644.txt
827+
M 100644 :2 :100644
828+
M 100644 :1 a100644.txt
829+
M 100644 :1 a100644
830+
831+
commit refs/heads/master
832+
mark :4
833+
author Joe <[email protected]> 1491387183 +0000
834+
committer Joe <[email protected]> 1491387183 +0000
835+
data 16
836+
(#12758) rename
837+
from :3
838+
D :100644
839+
M 100644 :2 :100666
840+
841+
reset refs/heads/master
842+
from :4
843+
"""
844+
781845
def _get_quickjump_names(self, repos):
782846
return list(name for type, name, path, rev
783847
in repos.get_quickjump_entries('HEAD'))

0 commit comments

Comments
 (0)