forked from importers/git-importer
Add actual tree and a test case for zsh
This commit is contained in:
@@ -2,40 +2,125 @@ from lib.db_revision import DBRevision
|
||||
from lib.request import Request
|
||||
|
||||
|
||||
class TreeNode:
|
||||
"""
|
||||
Nodes in this "tree" have either no parent (root), one parent (in a chain)
|
||||
or two parents (in this case the merged revision wins in conflicts).
|
||||
"""
|
||||
|
||||
def __init__(self, rev):
|
||||
self.parent = None
|
||||
self.merged = None
|
||||
self.revision = rev
|
||||
self.merged_into = None
|
||||
|
||||
def print(self):
|
||||
node = self
|
||||
while node:
|
||||
print(node.revision, node.revision.files_hash)
|
||||
if node.merged:
|
||||
source_node = node.merged
|
||||
while source_node:
|
||||
print(" ", source_node.revision, source_node.revision.files_hash)
|
||||
source_node = source_node.parent
|
||||
if source_node and source_node.merged_into:
|
||||
break
|
||||
node = node.parent
|
||||
|
||||
def as_list(self):
|
||||
"""Return a list for test cases"""
|
||||
node = self
|
||||
ret = []
|
||||
while node:
|
||||
repr = {"commit": node.revision.short_string()}
|
||||
if node.merged:
|
||||
source_node = node.merged
|
||||
repr["merged"] = []
|
||||
while source_node:
|
||||
repr["merged"].append(source_node.revision.short_string())
|
||||
source_node = source_node.parent
|
||||
if source_node and source_node.merged_into:
|
||||
break
|
||||
node = node.parent
|
||||
ret.append(repr)
|
||||
return ret
|
||||
|
||||
|
||||
class TreeBuilder:
|
||||
def __init__(self, db):
|
||||
self.db = db
|
||||
|
||||
def filtered_revisions(self, project, package):
|
||||
def revisions_chain(self, project, package):
|
||||
revisions = DBRevision.all_revisions(self.db, project, package)
|
||||
revisions.sort()
|
||||
ret = []
|
||||
prev = None
|
||||
tree = None
|
||||
for rev in revisions:
|
||||
if rev.broken:
|
||||
continue
|
||||
if prev and prev.files_hash == rev.files_hash:
|
||||
continue
|
||||
ret.append(rev)
|
||||
prev = rev
|
||||
return ret
|
||||
new_tree = TreeNode(rev)
|
||||
if tree:
|
||||
new_tree.parent = tree
|
||||
tree = new_tree
|
||||
|
||||
def build(self, package):
|
||||
factory_revisions = self.filtered_revisions("openSUSE:Factory", package)
|
||||
return tree
|
||||
|
||||
def find_merge(self, revision, source_chain):
|
||||
node = source_chain
|
||||
while node:
|
||||
# exclude reverts happening after the merge
|
||||
if (
|
||||
node.revision.commit_time <= revision.commit_time
|
||||
and node.revision.files_hash == revision.files_hash
|
||||
):
|
||||
return node
|
||||
node = node.parent
|
||||
|
||||
def add_merge_points(self, factory_revisions):
|
||||
source_revisions = dict()
|
||||
for rev in factory_revisions:
|
||||
print(rev, rev.files_hash)
|
||||
if rev.request_id:
|
||||
req = Request.find(self.db, rev.request_id)
|
||||
print(" ", req)
|
||||
factory_node = factory_revisions
|
||||
while factory_node:
|
||||
if factory_node.revision.request_id:
|
||||
req = Request.find(self.db, factory_node.revision.request_id)
|
||||
key = f"{req.source_project}/{req.source_package}"
|
||||
if key not in source_revisions:
|
||||
source_revisions[key] = self.filtered_revisions(
|
||||
source_revisions[key] = self.revisions_chain(
|
||||
req.source_project, req.source_package
|
||||
)
|
||||
for rev2 in source_revisions.get(key):
|
||||
# this happened after the fact - possibly a revert
|
||||
if rev2.commit_time > rev.commit_time:
|
||||
continue
|
||||
if rev2.files_hash == rev.files_hash:
|
||||
print(" ", rev2, rev2.files_hash)
|
||||
factory_node.merged = self.find_merge(
|
||||
factory_node.revision, source_revisions[key]
|
||||
)
|
||||
# add a reverse lookup
|
||||
if factory_node.merged:
|
||||
factory_node.merged.merged_into = factory_node
|
||||
|
||||
factory_node = factory_node.parent
|
||||
|
||||
def prune_loose_end(self, factory_node):
|
||||
"""Look for source revisions that end in a new root and prune them"""
|
||||
last_merge = None
|
||||
while factory_node:
|
||||
if factory_node.merged:
|
||||
source_node = factory_node.merged
|
||||
ended_without_merge = False
|
||||
while source_node:
|
||||
source_node = source_node.parent
|
||||
if source_node and source_node.merged_into:
|
||||
ended_without_merge = True
|
||||
break
|
||||
if not ended_without_merge:
|
||||
factory_node.merged = None
|
||||
last_merge.parent = None
|
||||
else:
|
||||
last_merge = factory_node.merged
|
||||
factory_node = factory_node.parent
|
||||
|
||||
def build(self, package):
|
||||
factory_revisions = self.revisions_chain("openSUSE:Factory", package)
|
||||
self.add_merge_points(factory_revisions)
|
||||
|
||||
self.prune_loose_end(factory_revisions)
|
||||
return factory_revisions
|
||||
|
Reference in New Issue
Block a user