app/check_includes.py
changeset 599 32a30f609530
parent 598 c1f9435bb645
child 600 f6abfcbff3a4
equal deleted inserted replaced
598:c1f9435bb645 599:32a30f609530
     1 #!/usr/bin/env python
       
     2 
       
     3 import sys
       
     4 
       
     5 import cPickle
       
     6 import os
       
     7 import graph
       
     8 
       
     9 
       
    10 ROOTDIR = "soc"
       
    11 
       
    12 
       
    13 def parseFile(file_name):
       
    14   if os.path.exists("imports.dat"):
       
    15     log = open("imports.dat", "r")
       
    16     all_imports = cPickle.load(log)
       
    17     log.close()
       
    18   else:
       
    19     all_imports = {}
       
    20 
       
    21   if file_name in all_imports:
       
    22     print "Overwriting previous data on '%s'." % file_name
       
    23 
       
    24   imports = []
       
    25 
       
    26   file = open(file_name)
       
    27 
       
    28   for line in file:
       
    29     if line.lstrip().startswith('import soc'):
       
    30       splitline = line[:-1].split(' ')
       
    31       mod = splitline[1]
       
    32       imports.append(mod)
       
    33 
       
    34     if line.lstrip().startswith('from soc'):
       
    35       splitline = line[:-1].split(' ')
       
    36       mod = splitline[1] + '.' + splitline[3]
       
    37       imports.append(mod)
       
    38 
       
    39   for idx, imp in enumerate(imports):
       
    40     if imp in set(imports[idx+1:]):
       
    41       sys.stderr.write("Warning: file '%s' has a redundant import: '%s'.\n" % (file_name, imp))
       
    42 
       
    43   if file_name.endswith("__init__.py"):
       
    44     normalized = file_name[:-12].replace('/', '.')
       
    45   else:
       
    46     normalized = file_name[:-3].replace('/', '.')
       
    47 
       
    48   print "Writing imports for file %s (%s)." % (file_name, normalized)
       
    49   all_imports[normalized] = imports
       
    50 
       
    51   log = open("imports.dat", "w")
       
    52   cPickle.dump(all_imports, log)
       
    53   log.close()
       
    54 
       
    55   return 0
       
    56 
       
    57 
       
    58 def buildGraph():
       
    59   if not os.path.exists("imports.dat"):
       
    60     sys.stderr.write("Missing imports.dat file, run 'build' first\n")
       
    61     return
       
    62 
       
    63   log = open("imports.dat", "r")
       
    64   all_imports = cPickle.load(log)
       
    65 
       
    66   gr = graph.digraph()
       
    67 
       
    68   gr.add_nodes(all_imports.keys())
       
    69 
       
    70   for file_name, imports in all_imports.iteritems():
       
    71     for imp in imports:
       
    72       gr.add_edge(file_name, imp)
       
    73 
       
    74   return gr
       
    75 
       
    76 
       
    77 def showGraph(gr):
       
    78   for node in gr:
       
    79     print "%s: " % node
       
    80     for edge in gr[node]:
       
    81       print "\t%s" % edge
       
    82 
       
    83   return 0
       
    84 
       
    85 
       
    86 def getParents(gst, target):
       
    87   parents = []
       
    88   current = target
       
    89 
       
    90   while True:
       
    91     for node in gst:
       
    92       if current in gst[node]:
       
    93         parents.append(node)
       
    94         current = node
       
    95         break
       
    96     else:
       
    97       break
       
    98 
       
    99   return parents
       
   100 
       
   101 
       
   102 def pathFrom(parents, first, target):
       
   103   idx = parents.index(first)
       
   104   path = parents[idx::-1]
       
   105   return [target] + path + [target]
       
   106 
       
   107 
       
   108 def findCycle(gr, gst, target):
       
   109   parents = getParents(gst, target)
       
   110   cycles = []
       
   111 
       
   112   for node in gr[target]:
       
   113     if node in parents:
       
   114       cycles.append(pathFrom(parents, node, target))
       
   115 
       
   116   return cycles
       
   117 
       
   118 
       
   119 def findCycles(gr):
       
   120   st, pre, post = gr.depth_first_search()
       
   121   gst = graph.digraph()
       
   122   gst.add_spanning_tree(st)
       
   123 
       
   124   cycles = []
       
   125 
       
   126   for node in gr:
       
   127     cycles += findCycle(gr, gst, node)
       
   128 
       
   129   return cycles
       
   130 
       
   131 
       
   132 def drawGraph(gr):
       
   133   st, pre, post = gr.depth_first_search()
       
   134   gst = graph.digraph()
       
   135   gst.add_spanning_tree(st)
       
   136 
       
   137   sys.path.append('/usr/lib/graphviz/python/')
       
   138   import gv
       
   139   dot = gst.write(fmt='dot')
       
   140   gvv = gv.readstring(dot)
       
   141   gv.layout(gvv,'dot')
       
   142   gv.render(gvv,'png','imports.png')
       
   143 
       
   144 
       
   145 def accumulate(arg, dirname, fnames):
       
   146   for fname in fnames:
       
   147     if not fname.endswith(".py"):
       
   148       continue
       
   149 
       
   150     arg.append(os.path.join(dirname, fname))
       
   151 
       
   152 
       
   153 def main(args):
       
   154   if len(args) != 1:
       
   155     print "Supported options: 'print', 'build', 'find', and 'draw'."
       
   156     return -1
       
   157 
       
   158   action = args[0]
       
   159 
       
   160   if action == "build":
       
   161     fnames = []
       
   162     os.path.walk(ROOTDIR, accumulate, fnames)
       
   163 
       
   164     for fname in fnames:
       
   165       parseFile(fname)
       
   166 
       
   167     print "Done parsing."
       
   168     return 0
       
   169 
       
   170   gr = buildGraph()
       
   171   if not gr:
       
   172     return 1
       
   173 
       
   174   if action == "show":
       
   175     return showGraph(gr)
       
   176 
       
   177   if action == "draw":
       
   178     return drawGraph(gr)
       
   179 
       
   180   if action == "find":
       
   181     cycles = findCycles(gr)
       
   182     for cycle in cycles:
       
   183       print cycle
       
   184     return 0
       
   185 
       
   186   print "Unknown option."
       
   187   return -1
       
   188 
       
   189 
       
   190 if __name__ == '__main__':
       
   191   import sys
       
   192   os.chdir("../app")
       
   193   res = main(sys.argv[1:])
       
   194   sys.exit(0)