Created
May 3, 2017 16:52
-
-
Save elpaso/f4a33583f40651e00e9f840dc3dbb1c9 to your computer and use it in GitHub Desktop.
Generate a report of Qt connection in cpp files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Create a graph of Qt connections | |
""" | |
import re | |
import glob | |
import sys | |
import tempfile | |
import argparse | |
from graphviz import Digraph | |
__author__ = 'Alessandro Pasotti' | |
__date__ = '03/05/2017' | |
__copyright__ = 'Copyright 2017, Boundlessgeo' | |
# This will get replaced with a git SHA1 when you do a git archive | |
__revision__ = '$Format:%H$' | |
RE=re.compile(r"connect\s*\(\s*([^\s,]+)\s*,\s*([^\s,]+)\s*,\s*([^\s,]+)\s*,\s*([^\s,]+)\s*\)") | |
connections = [] | |
class Connection(): | |
def __init__(self, signal, slot, path, line, txt): | |
self.signal = signal | |
self.slot = slot | |
self.path = path | |
self.line = line | |
self.txt = txt | |
def find_connections(path, include, exclude): | |
result = [] | |
with open(path) as f: | |
i = 1; | |
for line in f.readlines(): | |
try: | |
skip = False | |
_, signal, _, slot = RE.findall(line)[0] | |
if include and not re.search(include, line): | |
skip = True | |
if exclude and re.search(exclude, line): | |
skip = True | |
if not skip: | |
result.append(Connection(signal, slot, path, i, line)) | |
except Exception as e: | |
pass | |
i += 1 | |
return result | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-p", "--path", help="The path from where start to search for .cpp files. Defaults to current path", default=".") | |
parser.add_argument("-v", "--verbosity", help="Increase output verbosity", action="store_true") | |
parser.add_argument("-e", "--engine", help="Dot engine to use: dot, neato and fdp are supported", default='dot') | |
parser.add_argument("-x", "--exclude", help="Regexp to exclude certain classes or signals slots (it will be applied to both)") | |
parser.add_argument("-i", "--include", help="Regexp to include only certain classes or signals slots (it will be applied to both)") | |
args = parser.parse_args() | |
start = args.path | |
if not start.endswith('/'): | |
start = start + '/' | |
filter = sys.argv[2] if len(sys.argv) > 2 else None | |
for path in glob.glob('%s**/*.cpp' % start, recursive=True): | |
if args.verbosity: | |
print("Searching %s ... " % path) | |
connections.extend(find_connections(path, args.include, args.exclude)) | |
if len(connections): | |
dot = Digraph(comment='Signals and slots', engine=args.engine) | |
out = tempfile.mktemp('.dot') | |
signals = {} | |
slots = {} | |
edges = [] | |
def _mknode(signal, slot): | |
signal = signal.replace('&', '').replace('::', '-') | |
slot = slot.replace('&', '').replace('::', '-') | |
cls, si = signal.split('-') | |
if cls not in signals: | |
signals[cls] = [] | |
if si not in signals[cls]: | |
signals[cls].append(si) | |
cls, sl = slot.split('-') | |
if cls not in slots: | |
slots[cls] = [] | |
if sl not in slots[cls]: | |
slots[cls].append(sl) | |
edges.append((signal, slot)) | |
for c in connections: | |
try: | |
n = _mknode(c.signal, c.slot) | |
except: | |
print("Error parsing in %s : %s\n%s" % (c.path, c.line, c.txt)) | |
dot.attr('node', shape='rectangle') | |
for cls, sl in signals.items(): | |
with dot.subgraph(name='cluster_%s' % cls) as c: | |
c.attr(style='filled') | |
c.attr(color='lightgrey') | |
c.node_attr.update(style='filled', color='white') | |
[c.node("%s-%s" % (cls, s), s) for s in sl] | |
try: | |
c.node_attr.update(style='filled', color='yellow') | |
[c.node("%s-%s" % (cls, s), s) for s in slots[cls]] | |
del(slots[cls]) | |
except Exception as e: | |
pass | |
c.attr(label=cls) | |
for cls, sl in slots.items(): | |
if cls not in signals: | |
with dot.subgraph(name='cluster_%s' % cls) as c: | |
c.attr(style='filled') | |
c.attr(color='lightgrey') | |
c.node_attr.update(style='filled', color='white') | |
[c.node("%s-%s" % (cls, s), s) for s in sl] | |
c.attr(label=cls) | |
for e in edges: | |
dot.edge(*e) | |
if args.verbosity: | |
print("Dot stored in: %s" % out) | |
dot.render(out, view=True) | |
else: | |
print("Nothing found!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment