Skip to content

Commit

Permalink
Added parsing and output of dependency graph
Browse files Browse the repository at this point in the history
* parses Dependency.txt style files
* Outputs graphviz, or flat text
* as suggested by feature:
    BlueBrain#6
  • Loading branch information
mgeplf committed Mar 22, 2016
1 parent d252bc1 commit 0e0eb98
Showing 1 changed file with 142 additions and 0 deletions.
142 changes: 142 additions & 0 deletions utils/efel_graph_dependency
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/usr/bin/env python
'''graph the dependency graph'''

import argparse
import logging
import os

from collections import namedtuple, defaultdict

Feature = namedtuple('Feature', 'library name dependencies')
Dependency = namedtuple('Dependency', 'feature wildcard')


def create_feature(line):
'''Convert a line from the Dependency.txt to a feature
LibV2:AP_duration_half_width_change #LibV2:AP_duration_half_width
LibV2:E6 #LibV1:AP_amplitude;APWaveForm
'''
tokenized_line = line.strip().split()

library, name = '', tokenized_line[0]
if ':' in name:
library, name = name.strip().split(':')

dependencies = []
if len(tokenized_line) > 1:
dependencies.extend(create_dependency(d) for d in tokenized_line[1:])

return Feature(library=library, name=name, dependencies=dependencies)


def create_dependency(line):
'''parse a dependency, and create a Dependency'''
line = line.strip()
assert line[0] == '#', '"%s": Not a feature dependency, must start w/ #' % line
feature, wildcard = line[1:], ''
if ';' in feature:
feature, wildcard = feature.split(';')
return Dependency(feature=feature, wildcard=wildcard)


def get_feature_library(dependency_file):
'''parse the `dependency_file` and gather all the features and their dependencies'''
feature_library = defaultdict(dict)
with open(dependency_file) as fd:
for line in fd:
feature = create_feature(line)
feature_library[feature.library][feature.name] = feature
# defaults are the last to be loaded
feature_library['Default'][feature.name] = feature

def find_feature(dependency):
'''find the feature in the current feature_library'''
if ':' in dependency.feature:
library, name = dependency.feature.split(':')
else:
library, name = 'Default', dependency.feature
feature = feature_library[library][name]
return Dependency(feature=feature, wildcard=dependency.wildcard)

# resolve features pointers
for library in feature_library.keys():
if 'Default' == library:
continue
for feature in feature_library[library].values():
for i in range(len(feature.dependencies)):
feature.dependencies[i] = find_feature(feature.dependencies[i])

return feature_library


COLORS = ('blue', 'crimson', 'forestgreen', 'dodgerblue3', 'aquamarine4',
)


def output_graphivz(feature_library, filename, draw_dependencies=False,
output_dot=False):
'''create a PNG at filename of the dependencies'''
try:
import pygraphviz
except ImportError:
import sys
sys.exit('Need to have the "pygraphviz" package installed')
G = pygraphviz.AGraph(name='Dependencies', directed=True)
G.graph_attr['overlap'] = 'false'
G.graph_attr['rankdir'] = 'TB'

for library, color in zip(sorted(feature_library.keys()), COLORS):
if 'Default' == library:
continue
G.add_node(library, shape='circle', color=color)
sg = G.add_subgraph(name=library, style="")
for name, feature in feature_library[library].iteritems():
full_name = library + ':' + name
sg.add_node(full_name, label=name, shape='box', color=color)
sg.add_edge(library, full_name, color=color)
if draw_dependencies:
for dep in feature.dependencies:
target = dep.feature.library + ':' + dep.feature.name
G.add_edge(full_name, target, color='yellowgreen')

if output_dot:
G.write(os.path.splitext(filename)[0] + '.dot')
G.draw(filename, prog='dot')


def get_parser():
'''return the argument parser'''
parser = argparse.ArgumentParser()

parser.add_argument('-i', '--input', required=True,
help='Input Dependency.txt file')
parser.add_argument('-g', '--graph',
help='Output graph png file location')
parser.add_argument('--graph-deps', action='store_true',
help='If graphing, draw the links to the dependencies')
parser.add_argument('--dot', action='store_true',
help='If graphing, output the dot file')
parser.add_argument('-d', '--dump', action='store_true',
help='Dump the resolved dependency tree')
parser.add_argument('-v', '--verbose', action='count', default=0,
help='-v for INFO, -vv for DEBUG')
return parser


def main(args):
'''main'''
logging.basicConfig(level=(
logging.WARNING, logging.INFO, logging.DEBUG)[min(args.verbose, 2)])

feature_library = get_feature_library(args.input)
if args.dump:
from pprint import pprint
pprint(dict(feature_library))
if args.graph:
output_graphivz(feature_library, args.graph, args.graph_deps, args.dot)


if __name__ == '__main__':
PARSER = get_parser()
main(PARSER.parse_args())

0 comments on commit 0e0eb98

Please sign in to comment.