graphmod.py
127 lines
| 3.5 KiB
| text/x-python
|
PythonLexer
r2380 | """ | |||
Modified mercurial DAG graph functions that re-uses VCS structure | ||||
It allows to have a shared codebase for DAG generation for hg and git repos | ||||
""" | ||||
nullrev = -1 | ||||
def grandparent(parentrev_func, lowestrev, roots, head): | ||||
""" | ||||
Return all ancestors of head in roots which revision is | ||||
greater or equal to lowestrev. | ||||
""" | ||||
pending = set([head]) | ||||
seen = set() | ||||
kept = set() | ||||
llowestrev = max(nullrev, lowestrev) | ||||
while pending: | ||||
r = pending.pop() | ||||
if r >= llowestrev and r not in seen: | ||||
if r in roots: | ||||
kept.add(r) | ||||
else: | ||||
pending.update([p for p in parentrev_func(r)]) | ||||
seen.add(r) | ||||
return sorted(kept) | ||||
def _dagwalker(repo, revs, alias): | ||||
if not revs: | ||||
return | ||||
if alias == 'hg': | ||||
cl = repo._repo.changelog.parentrevs | ||||
repo = repo | ||||
elif alias == 'git': | ||||
def cl(rev): | ||||
return [x.revision for x in repo[rev].parents()] | ||||
repo = repo | ||||
lowestrev = min(revs) | ||||
gpcache = {} | ||||
knownrevs = set(revs) | ||||
for rev in revs: | ||||
ctx = repo[rev] | ||||
parents = sorted(set([p.revision for p in ctx.parents | ||||
if p.revision in knownrevs])) | ||||
mpars = [p.revision for p in ctx.parents if | ||||
p.revision != nullrev and p.revision not in parents] | ||||
for mpar in mpars: | ||||
gp = gpcache.get(mpar) | ||||
if gp is None: | ||||
gp = gpcache[mpar] = grandparent(cl, lowestrev, revs, mpar) | ||||
if not gp: | ||||
parents.append(mpar) | ||||
else: | ||||
parents.extend(g for g in gp if g not in parents) | ||||
yield (ctx.revision, 'C', ctx, parents) | ||||
def _colored(dag): | ||||
"""annotates a DAG with colored edge information | ||||
For each DAG node this function emits tuples:: | ||||
(id, type, data, (col, color), [(col, nextcol, color)]) | ||||
with the following new elements: | ||||
- Tuple (col, color) with column and color index for the current node | ||||
- A list of tuples indicating the edges between the current node and its | ||||
parents. | ||||
""" | ||||
seen = [] | ||||
colors = {} | ||||
newcolor = 1 | ||||
getconf = lambda rev: {} | ||||
for (cur, type, data, parents) in dag: | ||||
# Compute seen and next | ||||
if cur not in seen: | ||||
seen.append(cur) # new head | ||||
colors[cur] = newcolor | ||||
newcolor += 1 | ||||
col = seen.index(cur) | ||||
color = colors.pop(cur) | ||||
next = seen[:] | ||||
# Add parents to next | ||||
addparents = [p for p in parents if p not in next] | ||||
next[col:col + 1] = addparents | ||||
# Set colors for the parents | ||||
for i, p in enumerate(addparents): | ||||
if not i: | ||||
colors[p] = color | ||||
else: | ||||
colors[p] = newcolor | ||||
newcolor += 1 | ||||
# Add edges to the graph | ||||
edges = [] | ||||
for ecol, eid in enumerate(seen): | ||||
if eid in next: | ||||
bconf = getconf(eid) | ||||
edges.append(( | ||||
ecol, next.index(eid), colors[eid], | ||||
bconf.get('width', -1), | ||||
bconf.get('color', ''))) | ||||
elif eid == cur: | ||||
for p in parents: | ||||
bconf = getconf(p) | ||||
edges.append(( | ||||
ecol, next.index(p), color, | ||||
bconf.get('width', -1), | ||||
bconf.get('color', ''))) | ||||
# Yield and move on | ||||
yield (cur, type, data, (col, color), edges) | ||||
seen = next | ||||