summaryrefslogtreecommitdiffstats
path: root/src/ceph/doc/scripts/gen_state_diagram.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/ceph/doc/scripts/gen_state_diagram.py')
-rwxr-xr-xsrc/ceph/doc/scripts/gen_state_diagram.py214
1 files changed, 0 insertions, 214 deletions
diff --git a/src/ceph/doc/scripts/gen_state_diagram.py b/src/ceph/doc/scripts/gen_state_diagram.py
deleted file mode 100755
index fccde26..0000000
--- a/src/ceph/doc/scripts/gen_state_diagram.py
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/env python
-import re
-import sys
-
-
-def do_filter(generator):
- return acc_lines(remove_multiline_comments(to_char(remove_single_line_comments(generator))))
-
-
-def acc_lines(generator):
- current = ""
- for i in generator:
- current += i
- if i == ';' or \
- i == '{' or \
- i == '}':
- yield current.lstrip("\n")
- current = ""
-
-
-def to_char(generator):
- for line in generator:
- for char in line:
- if char is not '\n':
- yield char
- else:
- yield ' '
-
-
-def remove_single_line_comments(generator):
- for i in generator:
- if len(i) and i[0] == '#':
- continue
- yield re.sub(r'//.*', '', i)
-
-
-def remove_multiline_comments(generator):
- saw = ""
- in_comment = False
- for char in generator:
- if in_comment:
- if saw is "*":
- if char is "/":
- in_comment = False
- saw = ""
- if char is "*":
- saw = "*"
- continue
- if saw is "/":
- if char is '*':
- in_comment = True
- saw = ""
- continue
- else:
- yield saw
- saw = ""
- if char is '/':
- saw = "/"
- continue
- yield char
-
-
-class StateMachineRenderer(object):
- def __init__(self):
- self.states = {} # state -> parent
- self.machines = {} # state-> initial
- self.edges = {} # event -> [(state, state)]
-
- self.context = [] # [(context, depth_encountered)]
- self.context_depth = 0
- self.state_contents = {}
- self.subgraphnum = 0
- self.clusterlabel = {}
-
- def __str__(self):
- return "-------------------\n\nstates: %s\n\n machines: %s\n\n edges: %s\n\n context %s\n\n state_contents %s\n\n--------------------" % (
- self.states,
- self.machines,
- self.edges,
- self.context,
- self.state_contents
- )
-
- def read_input(self, input_lines):
- previous_line = None
- for line in input_lines:
- self.get_state(line)
- self.get_event(line)
- # pass two lines at a time to get the context so that regexes can
- # match on split signatures
- self.get_context(line, previous_line)
- previous_line = line
-
- def get_context(self, line, previous_line):
- match = re.search(r"(\w+::)*::(?P<tag>\w+)::\w+\(const (?P<event>\w+)", line)
- if match is None and previous_line is not None:
- # it is possible that we need to match on the previous line as well, so join
- # them to make them one line and try and get this matching
- joined_line = ' '.join([previous_line, line])
- match = re.search(r"(\w+::)*::(?P<tag>\w+)::\w+\(\s*const (?P<event>\w+)", joined_line)
- if match is not None:
- self.context.append((match.group('tag'), self.context_depth, match.group('event')))
- if '{' in line:
- self.context_depth += 1
- if '}' in line:
- self.context_depth -= 1
- while len(self.context) and self.context[-1][1] == self.context_depth:
- self.context.pop()
-
- def get_state(self, line):
- if "boost::statechart::state_machine" in line:
- tokens = re.search(
- r"boost::statechart::state_machine<\s*(\w*),\s*(\w*)\s*>",
- line)
- if tokens is None:
- raise Exception("Error: malformed state_machine line: " + line)
- self.machines[tokens.group(1)] = tokens.group(2)
- self.context.append((tokens.group(1), self.context_depth, ""))
- return
- if "boost::statechart::state" in line:
- tokens = re.search(
- r"boost::statechart::state<\s*(\w*),\s*(\w*)\s*,?\s*(\w*)\s*>",
- line)
- if tokens is None:
- raise Exception("Error: malformed state line: " + line)
- self.states[tokens.group(1)] = tokens.group(2)
- if tokens.group(2) not in self.state_contents.keys():
- self.state_contents[tokens.group(2)] = []
- self.state_contents[tokens.group(2)].append(tokens.group(1))
- if tokens.group(3) is not "":
- self.machines[tokens.group(1)] = tokens.group(3)
- self.context.append((tokens.group(1), self.context_depth, ""))
- return
-
- def get_event(self, line):
- if "boost::statechart::transition" in line:
- for i in re.finditer(r'boost::statechart::transition<\s*([\w:]*)\s*,\s*(\w*)\s*>',
- line):
- if i.group(1) not in self.edges.keys():
- self.edges[i.group(1)] = []
- if len(self.context) is 0:
- raise Exception("no context at line: " + line)
- self.edges[i.group(1)].append((self.context[-1][0], i.group(2)))
- i = re.search("return\s+transit<\s*(\w*)\s*>()", line)
- if i is not None:
- if len(self.context) is 0:
- raise Exception("no context at line: " + line)
- if self.context[-1][2] is "":
- raise Exception("no event in context at line: " + line)
- if self.context[-1][2] not in self.edges.keys():
- self.edges[self.context[-1][2]] = []
- self.edges[self.context[-1][2]].append((self.context[-1][0], i.group(1)))
-
- def emit_dot(self):
- top_level = []
- for state in self.machines.keys():
- if state not in self.states.keys():
- top_level.append(state)
- print >> sys.stderr, "Top Level States: ", str(top_level)
- print """digraph G {"""
- print '\tsize="7,7"'
- print """\tcompound=true;"""
- for i in self.emit_state(top_level[0]):
- print '\t' + i
- for i in self.edges.keys():
- for j in self.emit_event(i):
- print j
- print """}"""
-
- def emit_state(self, state):
- if state in self.state_contents.keys():
- self.clusterlabel[state] = "cluster%s" % (str(self.subgraphnum),)
- yield "subgraph cluster%s {" % (str(self.subgraphnum),)
- self.subgraphnum += 1
- yield """\tlabel = "%s";""" % (state,)
- yield """\tcolor = "blue";"""
- for j in self.state_contents[state]:
- for i in self.emit_state(j):
- yield "\t"+i
- yield "}"
- else:
- found = False
- for (k, v) in self.machines.items():
- if v == state:
- yield state+"[shape=Mdiamond];"
- found = True
- break
- if not found:
- yield state+";"
-
- def emit_event(self, event):
- def append(app):
- retval = "["
- for i in app:
- retval += (i + ",")
- retval += "]"
- return retval
- for (fro, to) in self.edges[event]:
- appendix = ['label="%s"' % (event,)]
- if fro in self.machines.keys():
- appendix.append("ltail=%s" % (self.clusterlabel[fro],))
- while fro in self.machines.keys():
- fro = self.machines[fro]
- if to in self.machines.keys():
- appendix.append("lhead=%s" % (self.clusterlabel[to],))
- while to in self.machines.keys():
- to = self.machines[to]
- yield("%s -> %s %s;" % (fro, to, append(appendix)))
-
-
-INPUT_GENERATOR = do_filter(sys.stdin.xreadlines())
-RENDERER = StateMachineRenderer()
-RENDERER.read_input(INPUT_GENERATOR)
-RENDERER.emit_dot()