summaryrefslogtreecommitdiff
path: root/tools/digest-log-file
blob: 58f90e68c2b7dadb56814e1b6169bcc80ec16ff5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/python
#
# Parse new-style logs (logs from the incremental resolver) and build
# digraphs from them.

import re

examining_re = re.compile('Examining step ([0-9]*) \(([0-9]*) actions\):')
generated_re = re.compile('Generated step ([0-9]*) \(([0-9]*) actions\) *:.*;T(\([^)]*\))S([0-9\\-]*)')
generating_successor_re = re.compile('Generating a successor to step ([0-9]*) for the action (.*) with tier (\([^)]*\)) and outputting to step ([0-9]*)')
forced_successor_re = re.compile('Following forced dependency resolution from step ([0-9]*) to step ([0-9]*)')
found_solution_re = re.compile('Found solution at step ([0-9]*):')
returned_re = re.compile('--- Returning the future solution .* from step ([0-9]*)')
install_choice_split_at_dep_re = re.compile(r'(Install[^(]*\([^<]*<(source: *)?)[^{]*{[^}]*}[^>]*>([^)]*\))')

import sys
import optparse

parser = optparse.OptionParser(usage = '%prog [OPTIONS] [INPUT ...]',
                               epilog='Process one or more input files and write them to separate graphs in the output file; defaults to reading from standard input and writing to standard output.')
parser.add_option('-o', '--output', metavar='FILE',
                  default='-',
                  help='Write output to FILE instead of to standard output ("-" for standard output).')



(opts, args) = parser.parse_args()

if opts.output == '-':
    outfile = sys.stdout
else:
    outfile = open(opts.output, 'w')


if len(args) == 0:
    args = ['-']

def collapse_choice(choice):
    return install_choice_split_at_dep_re.sub('\\1..>\\3', choice)

def flush_pending_edges(pending, pending_forced, outfile):
    for (start, finish, choice) in pending:
        attrs = { 'step1num' : start, 'step2num' : finish, 'choice' : collapse_choice(choice) }
        if pending_forced.get((start, finish), False):
            outfile.write('  "step%(step1num)s" -> "step%(step2num)s" [label="%(choice)s",color="black:black"];\n'
                          % attrs)
        else:
            outfile.write('  "step%(step1num)s" -> "step%(step2num)s" [label="%(choice)s"];\n'
                          % attrs)

try:
    for infilename in args:
        if infilename == '-':
            infile = sys.stdin
        else:
            infile = file(infilename)

        outfile.write('digraph {\n')

        try:
            # Lame-o hardcoded render of the root.
            outfile.write('  "step0" [shape=box, label="Root (0 actions)"];\n')

            pending_edges = []
            pending_forced = {}
            last_examined = None
            for line in infile:
                examining_match = examining_re.search(line)
                if examining_match:
                    flush_pending_edges(pending_edges, pending_forced, outfile)
                    pending_edges = []
                    pending_forced = {}

                    stepnum = examining_match.group(1)
                    if last_examined is not None:
                        outfile.write('  "step%(prevstepnum)s" -> "step%(stepnum)s" [style=dotted, color=blue, constraint=false];\n'
                                      % { "stepnum" : stepnum,
                                          "prevstepnum" : last_examined })

                    last_examined = stepnum

                generated_match = generated_re.search(line)
                if generated_match:
                    stepnum = generated_match.group(1)
                    actionnum = generated_match.group(2)
                    tier = generated_match.group(3)
                    score = generated_match.group(4)

                    outfile.write('  "step%(stepnum)s" [ shape=box, label="Step %(stepnum)s (%(actionnum)s actions)\\nScore: %(score)s; Tier: %(tier)s" ];\n'
                                  % { 'stepnum' : stepnum,
                                      'actionnum' : actionnum,
                                      'score' : score,
                                      'tier' : tier })

                generating_successor_match = generating_successor_re.search(line)
                if generating_successor_match:
                    parent = int(generating_successor_match.group(1))
                    child = int(generating_successor_match.group(4))
                    choice = generating_successor_match.group(2)
                    tier = generating_successor_match.group(3)
                    pending_edges.append((parent, child, choice))

                forced_successor_match = forced_successor_re.search(line)
                if forced_successor_match:
                    pending_forced[(int(forced_successor_match.group(1)),
                                    int(forced_successor_match.group(2)))] = True

                found_solution_match = found_solution_re.search(line)
                if found_solution_match:
                    outfile.write('  "step%(stepnum)s" [ style=filled, fillColor=lightgrey ];\n'
                                  % { 'stepnum' : found_solution_match.group(1) })

                returned_match = returned_re.search(line)
                if returned_match:
                    stepnum = returned_match.group(1)
                    outfile.write('  "step%s" [ peripheries=2 ];\n' % stepnum)
                    # Hack: draw a green line showing which step this
                    # was returned at.  Note that these always go *up*
                    # the tree, so a backwards arrow is used to avoid
                    # cycles.
                    if last_examined is not None:
                        outfile.write('  "step%(stepnum)s" -> "step%(prevstepnum)s" [style=dashed, color=green, dir=back, constraint=false];\n'
                                      % { "stepnum" : stepnum,
                                          "prevstepnum" : last_examined })

            flush_pending_edges(pending_edges, pending_forced, outfile)
            pending_edges = []
            pending_forced = {}
        finally:
            infile.close()

        outfile.write('}\n')
finally:
    outfile.close()