Alien-SVN
view release on metacpan or search on metacpan
src/subversion/tools/dev/mergegraph/mergegraph.py view on Meta::CPAN
import sys
import pydot
from pydot import Node, Edge
def mergeinfo_to_node_list(mi):
"""Convert a mergeinfo string such as '/foo:1,3-5*' into a list of
node names such as ['foo1', 'foo3', 'foo4', 'foo5'].
"""
### Doesn't yet strip the leading slash.
l = []
if mi:
for mi_str in mi.split(' '):
path, ranges = mi_str.split(':')
for r in ranges.split(','):
if r.endswith('*'):
# TODO: store & use this 'non-inheritable' flag
# Remove the flag
r = r[:-1]
rlist = r.split('-')
r1 = int(rlist[0])
if len(rlist) == 2:
r2 = int(rlist[1])
else:
r2 = r1
for rev in range(r1, r2 + 1):
l.append(path + str(rev))
return l
class MergeGraph(pydot.Graph):
"""Base class, not intended for direct use. Use MergeDot for the main
graph and MergeSubgraph for a subgraph.
"""
def mk_origin_node(graph, name, label):
"""Add a node to the graph"""
graph.add_node(Node(name, label=label, shape='plaintext'))
def mk_invis_node(graph, name):
"""Add a node to the graph"""
graph.add_node(Node(name, style='invis'))
def mk_node(graph, name, label=None):
"""Add a node to the graph, if not already present"""
if not graph.get_node(name):
if not label:
label = name
if name in graph.changes:
graph.add_node(Node(name, label=label))
else:
graph.add_node(Node(name, color='grey', label=''))
def mk_merge_target(graph, target_node, important):
"""Add a merge target node to the graph."""
if important:
color = 'red'
else:
color = 'black'
graph.add_node(Node(target_node, color=color, fontcolor=color, style='bold'))
def mk_edge(graph, name1, name2, **attrs):
"""Add an ordinary edge to the graph"""
graph.add_edge(Edge(name1, name2, dir='none', style='dotted', color='grey', **attrs))
def mk_br_edge(graph, name1, name2):
"""Add a branch-creation edge to the graph"""
# Constraint=false to avoid the Y-shape skewing the nice parallel branch lines
graph.mk_edge(name1, name2, constraint='false')
def mk_merge_edge(graph, src_node, tgt_node, kind, label, important):
"""Add a merge edge to the graph"""
if important:
color = 'red'
else:
color = 'grey'
e = Edge(src_node, tgt_node, constraint='false',
label='"' + label + '"',
color=color, fontcolor=color,
style='bold')
if kind.startswith('cherry'):
e.set_style('dashed')
graph.add_edge(e)
def mk_mergeinfo_edge(graph, base_node, src_node, important):
""""""
if important:
color = 'red'
else:
color = 'grey'
graph.add_edge(Edge(base_node, src_node,
dir='both', arrowtail='odot', arrowhead='tee',
color=color, constraint='false'))
def mk_invis_edge(graph, name1, name2):
"""Add an invisible edge to the graph"""
graph.add_edge(Edge(name1, name2, style='invis'))
def add_merge(graph, merge, important):
"""Add a merge"""
base_node, src_node, tgt_node, kind = merge
if base_node and src_node: # and not kind.startwith('cherry'):
graph.mk_mergeinfo_edge(base_node, src_node, important)
# Merge target node
graph.mk_merge_target(tgt_node, important)
# Merge edge
graph.mk_merge_edge(src_node, tgt_node, kind, kind, important)
def add_annotation(graph, node, label, color='lightblue'):
"""Add a graph node that serves as an annotation to a normal node.
More than one annotation can be added to the same normal node.
"""
subg_name = node + '_annotations'
def get_subgraph(graph, name):
"""Equivalent to pydot.Graph.get_subgraph() when there is no more than
one subgraph of the given name, but working aroung a bug in
pydot.Graph.get_subgraph().
"""
for subg in graph.get_subgraph_list():
if subg.get_name() == name:
return subg
return None
g = get_subgraph(graph, subg_name)
if not g:
g = pydot.Subgraph(subg_name, rank='same')
graph.add_subgraph(g)
ann_node = node + '_'
while g.get_node(ann_node):
ann_node = ann_node + '_'
g.add_node(Node(ann_node, shape='box', style='filled', color=color,
label='"' + label + '"'))
g.add_edge(Edge(ann_node, node, style='solid', color=color,
dir='none', constraint='false'))
( run in 1.164 second using v1.01-cache-2.11-cpan-5735350b133 )