--- a/Allura/allura/model/repo.py
+++ b/Allura/allura/model/repo.py
@@ -269,39 +269,71 @@
added.append(change.name)
else:
changed.append(change.name)
- prev_commit = self.log(1, 1)[0]
- for r_name in removed[:]:
- r_blob = prev_commit.tree.get_obj_by_path(r_name)
- r_type = 'blob' if isinstance(r_blob, Blob) else 'tree'
- best = dict(ratio=0, name='')
- for a_name in added:
- a_blob = self.tree.get_obj_by_path(a_name)
- if r_type == 'tree':
- if isinstance(a_blob, Tree):
- if r_blob._id == a_blob._id:
- best['ratio'] = 100
- best['name'] = a_name
- break;
- else:
- diff = SequenceMatcher(None, r_blob.text, a_blob.text)
- if diff.ratio() > best['ratio']:
- best['ratio'] = diff.ratio()
- best['name'] = a_name
- best['blob'] = a_blob
+ copied = self._diffs_copied(added, removed)
+ return Object(
+ added=added, removed=removed,
+ changed=changed, copied=copied)
+
+ def _diffs_copied(self, added, removed):
+ '''Return list with file renames diffs.
+
+ Will change `added` and `removed` lists also.
+ '''
+ def _blobs_similarity(removed_blob, added):
+ best = dict(ratio=0, name='', blob=None)
+ for added_name in added:
+ added_blob = self.tree.get_obj_by_path(added_name)
+ if not isinstance(added_blob, Blob):
+ continue
+ diff = SequenceMatcher(None, removed_blob.text,
+ added_blob.text)
+ ratio = diff.ratio()
+ if ratio > best['ratio']:
+ best['ratio'] = ratio
+ best['name'] = added_name
+ best['blob'] = added_blob
+
+ if ratio == 1:
+ break # we'll won't find better similarity than 100% :)
+
if best['ratio'] > DIFF_SIMILARITY_THRESHOLD:
diff = ''
if best['ratio'] < 1:
- a_blob = best['blob']
- diff = ''.join(unified_diff(list(r_blob), list(a_blob),
- ('a' + r_blob.path()).encode('utf-8'),
- ('b' + a_blob.path()).encode('utf-8')))
- copied.append(dict(old=r_name, new=best['name'],
- ratio=best['ratio'], diff=diff))
- removed.remove(r_name)
- added.remove(best['name'])
- return Object(
- added=added, removed=removed,
- changed=changed, copied=copied)
+ added_blob = best['blob']
+ rpath = ('a' + removed_blob.path()).encode('utf-8')
+ apath = ('b' + added_blob.path()).encode('utf-8')
+ diff = ''.join(unified_diff(list(removed_blob),
+ list(added_blob),
+ rpath, apath))
+ return dict(new=best['name'],
+ ratio=best['ratio'], diff=diff)
+
+ def _trees_similarity(removed_tree, added):
+ for added_name in added:
+ added_tree = self.tree.get_obj_by_path(added_name)
+ if not isinstance(added_tree, Tree):
+ continue
+ if removed_tree._id == added_tree._id:
+ return dict(new=added_name,
+ ratio=1, diff='')
+
+ if not removed:
+ return []
+ copied = []
+ prev_commit = self.log(1, 1)[0]
+ for removed_name in removed[:]:
+ removed_blob = prev_commit.tree.get_obj_by_path(removed_name)
+ rename_info = None
+ if isinstance(removed_blob, Blob):
+ rename_info = _blobs_similarity(removed_blob, added)
+ elif isinstance(removed_blob, Tree):
+ rename_info = _trees_similarity(removed_blob, added)
+ if rename_info is not None:
+ rename_info['old'] = removed_name
+ copied.append(rename_info)
+ removed.remove(rename_info['old'])
+ added.remove(rename_info['new'])
+ return copied
def get_path(self, path):
if path[0] == '/': path = path[1:]