diff options
author | Simon Warta <[email protected]> | 2015-06-23 14:00:08 +0200 |
---|---|---|
committer | Simon Warta <[email protected]> | 2015-06-23 14:00:08 +0200 |
commit | 06ea8f6e93bb40bef35ffb85e3a3f3156b3fdc1f (patch) | |
tree | 20baa79e3f53e4cf68183fa2d9042a1afc955324 /src/scripts/show_dependencies.py | |
parent | 2a83523815461a4aa461ce5cc3b1288727440705 (diff) |
Add script that shows Botan module dependencies
Diffstat (limited to 'src/scripts/show_dependencies.py')
-rwxr-xr-x | src/scripts/show_dependencies.py | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/scripts/show_dependencies.py b/src/scripts/show_dependencies.py new file mode 100755 index 000000000..cee46a277 --- /dev/null +++ b/src/scripts/show_dependencies.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python + +# global +import argparse +import sys +import subprocess +from collections import OrderedDict +import glob +import os + +# Assume this script is in botan/src/scripts +botan_root = os.path.join(os.path.dirname(sys.argv[0]), "..", "..") + +# locale +sys.path.append(botan_root) +from configure import ModuleInfo + +parser = argparse.ArgumentParser(description= + 'Show Botan module dependencies. ' + 'The output is reduced by indirect dependencies, ' + 'i.e. you must look at the result recursively to get all dependencies.') + +parser.add_argument('mode', + choices=["list", "draw"], + help='The output mode') +parser.add_argument('--format', + nargs='?', + choices=["pdf", "png"], + default="pdf", + help='The file format (drawing mode only)') +parser.add_argument('--engine', + nargs='?', + choices=["fdp", "dot"], + default="fdp", + help='The graph engine (drawing mode only)') +parser.add_argument('--verbose', dest='verbose', action='store_const', + const=True, default=False, + help='Verbose output (default: false)') +args = parser.parse_args() + +files = [] +files += glob.glob(botan_root + '/src/lib/*/*/*/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/info.txt') +files += glob.glob(botan_root + '/src/lib/info.txt') +files.sort() + +if len(files) == 0: + print("No info.txt files found.") + sys.exit(1) + +modules = [] + +def dicts(t): return {k: dicts(t[k]) for k in t} + +def paths(t, path = [], level=0): + ret = [] + for key in t: + ret.append(path + [key]) + ret += paths(t[key], path + [key], level+1) + return ret + +if args.verbose: + print("Getting dependencies from into.txt files ...") + +for filename in files: + (rest, info_txt) = os.path.split(filename) + (rest, modname) = os.path.split(rest) + module = ModuleInfo(filename) + modules.append(module) + if args.verbose: + print(module.basename) + print("\t" + str(set(module.dependencies()))) + +if args.verbose: + print(str(len(modules)) + " modules:") + names=[m.basename for m in modules] + names.sort() + print(names) + print("") + +if args.verbose: + print("resolving dependencies ...") + +all_dependencies = dict() +direct_dependencies = dict() + +for module in modules: + lst = module.dependencies() + direct_dependencies[module.basename] = set(lst) + +all_dependencies = direct_dependencies.copy() + +#print(direct_dependencies) + +def cartinality(depdict): + return sum([len(depdict[k]) for k in depdict]) + +# Sort +direct_dependencies = OrderedDict(sorted(direct_dependencies.items())) + +def depends_on(a, b): + if not a in all_dependencies: + return False + else: + return b in all_dependencies[a] + +def remove_indirect_dependencies(): + for mod in direct_dependencies: + for one in direct_dependencies[mod]: + others = direct_dependencies[mod] - set([one]) + for other in others: + if depends_on(one, other): + direct_dependencies[mod].remove(one) + return + # Go to next mod + +last_card = -1 +while True: + card = cartinality(direct_dependencies) + # print(card) + if card == last_card: + break; + last_card = card + remove_indirect_dependencies() + +def openfile(f): + if sys.platform.startswith('linux'): + subprocess.call(["xdg-open", f]) + else: + os.startfile(f) + +if args.verbose: + print("Done resolving dependencies.") + +if args.mode == "list": + for key in direct_dependencies: + print(key.ljust(17) + " : " + ", ".join(sorted(direct_dependencies[key]))) + +if args.mode == "draw": + import graphviz as gv + import tempfile + + tmpdir = tempfile.mkdtemp(prefix="botan-") + + g2 = gv.Digraph(format=args.format, engine=args.engine) + for key in direct_dependencies: + g2.node(key) + for dep in direct_dependencies[key]: + g2.edge(key, dep) + + if args.verbose: + print("Rendering graph ...") + filename = g2.render(filename='graph', directory=tmpdir) + + if args.verbose: + print("Opening " + filename + " ...") + openfile(filename) + |