aboutsummaryrefslogtreecommitdiffstats
path: root/src/scripts/show_dependencies.py
diff options
context:
space:
mode:
authorSimon Warta <[email protected]>2015-06-23 14:00:08 +0200
committerSimon Warta <[email protected]>2015-06-23 14:00:08 +0200
commit06ea8f6e93bb40bef35ffb85e3a3f3156b3fdc1f (patch)
tree20baa79e3f53e4cf68183fa2d9042a1afc955324 /src/scripts/show_dependencies.py
parent2a83523815461a4aa461ce5cc3b1288727440705 (diff)
Add script that shows Botan module dependencies
Diffstat (limited to 'src/scripts/show_dependencies.py')
-rwxr-xr-xsrc/scripts/show_dependencies.py162
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)
+