Rewrite matrix-graph for the new internal structure.
authorKalle Vahlman <kalle.vahlman@movial.com>
Wed, 22 Oct 2008 16:52:05 +0000 (19:52 +0300)
committerKalle Vahlman <kalle.vahlman@movial.fi>
Wed, 22 Oct 2008 17:00:16 +0000 (20:00 +0300)
The old components files are not sensible anymore so that style was dropped.
Also we don't generate the final graphics anymore, that is left to the user.

bin/matrix-graph
matrix/graph.py

index 5c424c8..8738cd8 100755 (executable)
@@ -10,28 +10,18 @@ if moduledir.startswith('@'):
 
 sys.path.insert(0, moduledir)
 
-from matrix import graph
+from matrix import graph, log
 
-commands = [
-       ("components", graph.ComponentGraph, "Create a components file from the dependancy tree"),
-       ("dot", graph.DotGraph, "Create a graph from the dependancy tree with 'dot'"),
-]
+try:
+       graph.main()
 
-print "\nCopyright (C) 2007-2008 Movial Oy\n"
+except RuntimeError, e:
+       msg = str(e)
+       if msg:
+               log.error(msg)
 
-if len(sys.argv) < 2:
-       print "Please specify one of the following commands:\n"
-       for command, obj, description in commands:
-               print "  %-15s %s" % (command, description)
-       print
-       sys.exit(1)
+except KeyboardInterrupt:
+       log.message('Interrupted')
 
-if sys.argv[1] == "components":
-       g = graph.ComponentGraph(sys.argv[2:])
-elif sys.argv[1] == "dot":
-       g = graph.DotGraph(sys.argv[2:])
-else:
-       print "Unknown command", sys.argv[1]
+if log.dump():
        sys.exit(1)
-  
-g.output()
index 54bbdc5..5fb62f1 100644 (file)
 
 import os
 import sys
+import optparse
 
 import components
+
 from config import config
+from config import parse as config_parse
+
+def print_help(file, parser):
+       parser.print_help(file=file)
+       print >>file, '''
+commands:
+  dot          Create a graph with the 'dot' utility
+'''
+
+class Dot:
+       def header(this):
+               return "digraph {"
+
+       def footer(this):
+               return "}"
+
+       def dependancy(this, c, d):
+               return "\t\"" + c.name + "\" -> \"" + d.name + "\""
+
+cmds = {
+       "dot" : Dot(),
+}
+
+deps = []
+lines = []
+ignored_components = []
+
+def main():
+       def append_config_dir(option, opt, value, parser):
+               config.initial_config_dirs.append(value)
+
+       def append_ignored_component(option, opt, value, parser):
+               ignored_components.append(value)
+
+       parser = optparse.OptionParser(usage='%prog [<options>] [<component>]')
+
+       parser.add_option(
+               '-c', '--config-dir', metavar='DIR',
+               help='add a directory for finding config files ' \
+                       '(may be set multiple times)',
+               dest='initial_config_dirs', action='callback',
+               callback=append_config_dir, type='string')
+
+       parser.add_option(
+               '-i', '--ignore', metavar='COMPONENT',
+               help='add a component to be ignored ' \
+                       '(may be set multiple times)',
+               dest='ignored_components', action='callback',
+               callback=append_ignored_component, type='string')
+
+       values, args = parser.parse_args(values=None)
+
+       if not args:
+               print_help(sys.stderr, parser)
+               sys.exit(1)
+
+       try:
+               chart = cmds[args[0]]
+               targets = args[1:]
+       except KeyError:
+               print "Not a valid command:", args[0]
+               print_help(sys.stderr, parser)
+               sys.exit(1)
+               
+       config_parse('main')
+
+       components.init(targets)
+
+       print chart.header()
+
+       if len(targets) == 0:
+               targets = components.by_name.values()
+
+       for component in targets:
+               do_component_graph(component, chart.dependancy)
+       for line in lines:
+               print line
+       print chart.footer()
+       
+def do_component_graph(c, dfun):
+
+       for dep in c.get_depends():
+               if dep.name in ignored_components:
+                       return
+               if dep.rank != 0:
+                       continue
+               if dep not in deps:
+                       deps.append(dep)
+
+               depstr = dfun(c, dep)
+               if depstr not in lines:
+                       lines.append(depstr)
+               do_component_graph(dep, dfun)
 
 
-class Option(object):
-       short_opt = None
-       long_opt = None
-       takes_arg = False
-       help = None
-       argument = None
-
-       def __init__(self, short_opt, long_opt, takes_arg, help):
-               self.short_opt = short_opt
-               self.long_opt = long_opt
-               self.takes_arg = takes_arg
-               self.help = help
-
-
-class Graph(object):
-       all_targets = []
-       all_deps = []
-       maxdepth = -1
-
-       options = {}
-       args = []
-       roots = None
-
-       def __init__(self, arguments):
-               self.args.append(Option("h", "help", False,
-                       "Show this help"))
-               self.args.append(Option("c", "components", True,
-                       "Read components from specified file (default: 'components.all')"))
-               self.args.append(Option("i", "input", True,
-                       "Read active components from specified file"))
-               self.args.append(Option("o", "output", True,
-                       "Write graph to specified file (type autodetected)"))
-               self.args.append(Option("r", "root", True,
-                       "Start graphing from specified component"))
-               self.args.append(Option("d", "depth", True,
-                       "Limit graph to specified depth"))
-
-               self.parse_args(arguments)
-
-               try:
-                       if self.options["help"]:
-                               print "\nCopyright (C) 2007 Movial Oy\n"
-                               print "Usage: %s [options]\n" % sys.argv[0]
-
-                               for opt in self.args:
-                                       argstr = ""
-                                       if opt.takes_arg:
-                                               argstr = "[arg]"
-
-                                       print " %-25s %s" % ("-" + opt.short_opt + ", --" + opt.long_opt + " " + argstr, opt.help)
-                       print
-                       sys.exit()
-               except KeyError:
-                       pass
-
-               try:
-                       config.parse(self.options["components"].argument)
-               except KeyError:
-                       # Default to components.all
-                       config.parse('components/components.all')
-                       print "huuhaaaaaa"
-
-               components.init()
-
-               try:
-                       self.maxdepth = int(self.options["depth"].argument)
-               except KeyError:
-                       self.maxdepth = -1
-
-               roots = self.get_roots()
-
-               depth = 1
-               for component in components.by_name.values():
-                       if roots is None or component.name in roots:
-
-                               self.add_component(component, self.maxdepth, depth)
-
-       def add_component(self, component, maxdepth, depth):
-               for dep in component.active_depends:
-                       dependancy = self.depends(component, dep)
-                       if dependancy not in self.all_deps:
-                               self.all_deps.append(dependancy)
-                       if maxdepth < 0 or depth < maxdepth:
-                               self.add_component(dep, maxdepth, depth + 1)
-
-       def parse_args(self, arguments):
-               arg = None
-               argarg = None
-               for argument in arguments:
-                       if arg is not None and arg.takes_arg:
-                               if not argument.startswith("-"):
-                                       arg.argument = argument
-                                       arg = None
-                                       continue
-                               else:
-                                       arg = None
-
-                       for opt in self.args:
-                               if argument.startswith("-") or argument.startswith("--"):
-                                       if argument[1:] == opt.short_opt or argument[2:] == opt.long_opt:
-                                               self.options[opt.long_opt] = opt
-                                               arg = opt
-                                               break
-
-                       if arg is None:
-                               raise RuntimeError, "Unkown argument '" + argument + "'"
-
-       def read_roots(self, active_components_file="components.active"):
-               f = open(active_components_file, "r")
-               self.roots = []
-               for root in f.readlines():
-                       if len(root.strip()) > 0:
-                               self.roots.append(root.strip())
-               f.close()
-               print "Active components read from", active_components_file
-
-       def get_roots(self):
-               if self.roots is not None:
-                       return self.roots
-
-               try:
-                       active_components_file = self.options["input"].argument
-                       self.read_roots(active_components_file)
-               except KeyError:
-                       try:
-                               self.read_roots()
-                       except IOError:
-                               try:
-                                       self.roots = [self.options["root"].argument]
-                                       print "Active component: %s" % self.roots[0]
-                               except KeyError:
-                                       print "Including all known components as active"
-
-               return self.roots
-
-       def depends(self, component, dependancy):
-               raise NotImplementedError, 'Method depends not implemented by derived class'
-
-       def output(self):
-               raise NotImplementedError, 'Method output not implemented by derived class'
-
-
-class DotGraph(Graph):
-       def __init__(self, arguments):
-               self.args.append(Option("a", "aspect-ratio", True,
-                       "Dot: Aspect ratio for the graph"))
-               self.args.append(Option("s", "size", True,
-                       "Dot: Size of the graph ('xx.x,xx.x', in inches)"))
-               Graph.__init__(self, arguments)
-
-       def depends(self, component, dependancy):
-               return "\t\"" + component.name + "\" -> \"" + dependancy.name + "\""
-
-       def output(self):
-               try:
-                       fname = self.options["output"].argument
-                       otype = self.options["output"].argument[self.options["output"].argument.rindex(".")+1:]
-               except KeyError:
-                       fname = "graph.svg"
-                       otype = "svg"
-
-               try:
-                       ratio = self.options["aspect"].argument
-               except KeyError:
-                       ratio = "0.7" # default to landscape A4
-
-               try:
-                       size = "-Gsize=" + self.options["size"].argument
-               except KeyError:
-                       size = '' # default to native size
-
-               f = open("graph.dot", "w")
-               f.write("digraph {\n")
-               for depstr in self.all_deps:
-                       f.write(depstr + "\n")
-               f.write("}\n")
-               f.close()
-
-               print "Writing", fname
-               os.system("dot graph.dot -Grankdir=LR -Gsplines=true -Nrotate=90 -Gratio=" + ratio + " -T" + otype + " " + size + " -o " + fname)
-               os.remove("graph.dot")
-
-class ComponentGraph(Graph):
-       def __init__(self, arguments):
-               Graph.__init__(self, arguments)
-
-               if self.roots is not None:
-                       for component in components.by_name.values():
-                               if component.name in self.roots:
-                                       self.all_deps.append(self.depends(None, component))
-                                       break
-
-       def depends(self, component, dependancy):
-               tagstr = ""
-               flagstr = ""
-               if dependancy.tags[None] != "matrix":
-                       tagstr = ",\ttag='" + dependancy.tags[None] + "'"
-               if len(dependancy.flags) > 0:
-                       flagstr = ",\tflags=["
-                       for flag in dependancy.flags:
-                               flagstr += "'" + flag + "',"
-                       flagstr = flagstr[:-1] + "]"
-
-               return "Component('" + dependancy.name + "'" + tagstr + flagstr + ")"
-
-       def output(self):
-               try:
-                       fname = self.options["output"].argument
-               except KeyError:
-                       fname = "components"
-
-               print "Writing", fname
-               f = open(fname, "w")
-               for depstr in self.all_deps:
-                       f.write(depstr + "\n")
-               f.close()