1#!/usr/bin/env python
2# vim: ts=2 sw=2
3
4import optparse
5import re
6import sys
7
8
9class Dependency:
10  def __init__(self, tgt):
11    self.tgt = tgt
12    self.pos = ""
13    self.prereqs = set()
14    self.visit = 0
15
16  def add(self, prereq):
17    self.prereqs.add(prereq)
18
19
20class Dependencies:
21  def __init__(self):
22    self.lines = {}
23    self.__visit = 0
24    self.count = 0
25
26  def add(self, tgt, prereq):
27    t = self.lines.get(tgt)
28    if not t:
29      t = Dependency(tgt)
30      self.lines[tgt] = t
31    p = self.lines.get(prereq)
32    if not p:
33      p = Dependency(prereq)
34      self.lines[prereq] = p
35    t.add(p)
36    self.count = self.count + 1
37
38  def setPos(self, tgt, pos):
39    t = self.lines.get(tgt)
40    if not t:
41      t = Dependency(tgt)
42      self.lines[tgt] = t
43    t.pos = pos
44
45  def get(self, tgt):
46    if self.lines.has_key(tgt):
47      return self.lines[tgt]
48    else:
49      return None
50
51  def __iter__(self):
52    return self.lines.iteritems()
53
54  def trace(self, tgt, prereq):
55    self.__visit = self.__visit + 1
56    d = self.lines.get(tgt)
57    if not d:
58      return
59    return self.__trace(d, prereq)
60
61  def __trace(self, d, prereq):
62    if d.visit == self.__visit:
63      return d.trace
64    if d.tgt == prereq:
65      return [ [ d ], ]
66    d.visit = self.__visit
67    result = []
68    for pre in d.prereqs:
69      recursed = self.__trace(pre, prereq)
70      for r in recursed:
71        result.append([ d ] + r)
72    d.trace = result
73    return result
74
75def help():
76  print "Commands:"
77  print "  dep TARGET             Print the prerequisites for TARGET"
78  print "  trace TARGET PREREQ    Print the paths from TARGET to PREREQ"
79
80
81def main(argv):
82  opts = optparse.OptionParser()
83  opts.add_option("-i", "--interactive", action="store_true", dest="interactive",
84                    help="Interactive mode")
85  (options, args) = opts.parse_args()
86
87  deps = Dependencies()
88
89  filename = args[0]
90  print "Reading %s" % filename
91
92  if True:
93    f = open(filename)
94    for line in f:
95      line = line.strip()
96      if len(line) > 0:
97        if line[0] == '#':
98          pos,tgt = line.rsplit(":", 1)
99          pos = pos[1:].strip()
100          tgt = tgt.strip()
101          deps.setPos(tgt, pos)
102        else:
103          (tgt,prereq) = line.split(':', 1)
104          tgt = tgt.strip()
105          prereq = prereq.strip()
106          deps.add(tgt, prereq)
107    f.close()
108
109  print "Read %d dependencies. %d targets." % (deps.count, len(deps.lines))
110  while True:
111    line = raw_input("target> ")
112    if not line.strip():
113      continue
114    split = line.split()
115    cmd = split[0]
116    if len(split) == 2 and cmd == "dep":
117      tgt = split[1]
118      d = deps.get(tgt)
119      if d:
120        for prereq in d.prereqs:
121          print prereq.tgt
122    elif len(split) == 3 and cmd == "trace":
123      tgt = split[1]
124      prereq = split[2]
125      if False:
126        print "from %s to %s" % (tgt, prereq)
127      trace = deps.trace(tgt, prereq)
128      if trace:
129        width = 0
130        for g in trace:
131          for t in g:
132            if len(t.tgt) > width:
133              width = len(t.tgt)
134        for g in trace:
135          for t in g:
136            if t.pos:
137              print t.tgt, " " * (width-len(t.tgt)), "  #", t.pos
138            else:
139              print t.tgt
140          print
141    else:
142      help()
143
144if __name__ == "__main__":
145  try:
146    main(sys.argv)
147  except KeyboardInterrupt:
148    print
149  except EOFError:
150    print
151
152