scripts/check_includes.py
changeset 599 32a30f609530
parent 598 c1f9435bb645
child 600 f6abfcbff3a4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/check_includes.py	Thu Nov 27 23:41:08 2008 +0000
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+
+import sys
+
+import cPickle
+import os
+import graph
+
+
+ROOTDIR = "soc"
+
+
+def parseFile(file_name):
+  if os.path.exists("imports.dat"):
+    log = open("imports.dat", "r")
+    all_imports = cPickle.load(log)
+    log.close()
+  else:
+    all_imports = {}
+
+  if file_name in all_imports:
+    print "Overwriting previous data on '%s'." % file_name
+
+  imports = []
+
+  file = open(file_name)
+
+  for line in file:
+    if line.lstrip().startswith('import soc'):
+      splitline = line[:-1].split(' ')
+      mod = splitline[1]
+      imports.append(mod)
+
+    if line.lstrip().startswith('from soc'):
+      splitline = line[:-1].split(' ')
+      mod = splitline[1] + '.' + splitline[3]
+      imports.append(mod)
+
+  for idx, imp in enumerate(imports):
+    if imp in set(imports[idx+1:]):
+      sys.stderr.write("Warning: file '%s' has a redundant import: '%s'.\n" % (file_name, imp))
+
+  if file_name.endswith("__init__.py"):
+    normalized = file_name[:-12].replace('/', '.')
+  else:
+    normalized = file_name[:-3].replace('/', '.')
+
+  print "Writing imports for file %s (%s)." % (file_name, normalized)
+  all_imports[normalized] = imports
+
+  log = open("imports.dat", "w")
+  cPickle.dump(all_imports, log)
+  log.close()
+
+  return 0
+
+
+def buildGraph():
+  if not os.path.exists("imports.dat"):
+    sys.stderr.write("Missing imports.dat file, run 'build' first\n")
+    return
+
+  log = open("imports.dat", "r")
+  all_imports = cPickle.load(log)
+
+  gr = graph.digraph()
+
+  gr.add_nodes(all_imports.keys())
+
+  for file_name, imports in all_imports.iteritems():
+    for imp in imports:
+      gr.add_edge(file_name, imp)
+
+  return gr
+
+
+def showGraph(gr):
+  for node in gr:
+    print "%s: " % node
+    for edge in gr[node]:
+      print "\t%s" % edge
+
+  return 0
+
+
+def getParents(gst, target):
+  parents = []
+  current = target
+
+  while True:
+    for node in gst:
+      if current in gst[node]:
+        parents.append(node)
+        current = node
+        break
+    else:
+      break
+
+  return parents
+
+
+def pathFrom(parents, first, target):
+  idx = parents.index(first)
+  path = parents[idx::-1]
+  return [target] + path + [target]
+
+
+def findCycle(gr, gst, target):
+  parents = getParents(gst, target)
+  cycles = []
+
+  for node in gr[target]:
+    if node in parents:
+      cycles.append(pathFrom(parents, node, target))
+
+  return cycles
+
+
+def findCycles(gr):
+  st, pre, post = gr.depth_first_search()
+  gst = graph.digraph()
+  gst.add_spanning_tree(st)
+
+  cycles = []
+
+  for node in gr:
+    cycles += findCycle(gr, gst, node)
+
+  return cycles
+
+
+def drawGraph(gr):
+  st, pre, post = gr.depth_first_search()
+  gst = graph.digraph()
+  gst.add_spanning_tree(st)
+
+  sys.path.append('/usr/lib/graphviz/python/')
+  import gv
+  dot = gst.write(fmt='dot')
+  gvv = gv.readstring(dot)
+  gv.layout(gvv,'dot')
+  gv.render(gvv,'png','imports.png')
+
+
+def accumulate(arg, dirname, fnames):
+  for fname in fnames:
+    if not fname.endswith(".py"):
+      continue
+
+    arg.append(os.path.join(dirname, fname))
+
+
+def main(args):
+  if len(args) != 1:
+    print "Supported options: 'print', 'build', 'find', and 'draw'."
+    return -1
+
+  action = args[0]
+
+  if action == "build":
+    fnames = []
+    os.path.walk(ROOTDIR, accumulate, fnames)
+
+    for fname in fnames:
+      parseFile(fname)
+
+    print "Done parsing."
+    return 0
+
+  gr = buildGraph()
+  if not gr:
+    return 1
+
+  if action == "show":
+    return showGraph(gr)
+
+  if action == "draw":
+    return drawGraph(gr)
+
+  if action == "find":
+    cycles = findCycles(gr)
+    for cycle in cycles:
+      print cycle
+    return 0
+
+  print "Unknown option."
+  return -1
+
+
+if __name__ == '__main__':
+  import sys
+  os.chdir("../app")
+  res = main(sys.argv[1:])
+  sys.exit(0)