1import json
2
3class Trace(object):
4    """
5    An llbuild build system trace
6    """
7
8    # Get a cached trace.
9    @classmethod
10    def frompath(cls, path):
11        db = cls._traces.get(path)
12        if db is None:
13            cls._traces[path] = db = Trace(path)
14        return db
15    _traces = {}
16
17    def __init__(self, path):
18        self.events = []
19        self.tasks = {}
20        self.rules = {}
21
22        # FIXME: Move this format to just JSON for ease of loading.
23        with open(path) as f:
24            lines = list(f)
25            print((lines[0], lines[-1]))
26            assert(lines.pop(0) == '[\n')
27            assert(lines.pop(-1) == ']\n')
28            for line in lines:
29                assert(line.startswith('{ '))
30                assert(line.endswith('},\n'))
31                line = line[2:-3]
32                event_data = [eval(s) for s in line.split(', ')]
33                handler = _event_handlers.get(event_data[0])
34                if handler is None:
35                    raise NotImplementedError(
36                        "unknown event: {}".format(event_data[0]))
37                event = handler(self, event_data[1:])
38                if event:
39                    self.events.append(event)
40
41# MARK: Event Parsing
42
43class Rule(object):
44    def __init__(self, data):
45        (name, key) = data
46        self.name = name
47        self.key = key
48
49class Task(object):
50    def __init__(self, data):
51        (name,) = data
52        self.name = name
53        self.rule = None
54
55###
56
57class Event(object):
58    @property
59    def isReadiedTask(self):
60        return isinstance(self, ReadiedTask)
61
62class BuildStarted(Event):
63    def __init__(self, trace, data):
64        pass
65
66class BuildEnded(Event):
67    def __init__(self, trace, data):
68        pass
69
70class HandlingBuildInputRequest(Event):
71    def __init__(self, trace, data):
72        (rule,) = data
73        self.rule = trace.rules[rule]
74
75class CheckingRuleNeedsToRun(Event):
76    def __init__(self, trace, data):
77        (rule,) = data
78        self.rule = trace.rules[rule]
79
80class RuleNeedsToRun(Event):
81    class NeverBuilt(Event):
82        pass
83    class InvalidValue(Event):
84        pass
85    class InputRebuilt(Event):
86        def __init__(self, inputRule):
87            self.inputRule = inputRule
88    def __init__(self, trace, data):
89        self.rule = trace.rules[data[0]]
90        if data[1] == 'invalid-value':
91            (_, _) = data
92            self.reason = RuleNeedsToRun.InvalidValue()
93        elif data[1] == 'never-built':
94            (_, _) = data
95            self.reason = RuleNeedsToRun.NeverBuilt()
96        elif data[1] == 'input-rebuilt':
97            (_, _, inputRule) = data
98            self.reason = RuleNeedsToRun.InputRebuilt(
99                trace.rules[inputRule])
100        else:
101            raise NotImplementedError("unknown reason: {}".format(data))
102
103class RuleDoesNotNeedToRun(Event):
104    def __init__(self, trace, data):
105        (rule,) = data
106        self.rule = trace.rules[rule]
107
108class CreatedTaskForRule(Event):
109    def __init__(self, trace, data):
110        (task, rule) = data
111        self.task = trace.tasks[task]
112        self.rule = trace.rules[rule]
113        self.task.rule = self.rule
114
115class HandlingTaskInputRequest(Event):
116    def __init__(self, trace, data):
117        (task, rule) = data
118        self.task = trace.tasks[task]
119        self.rule = trace.rules[rule]
120
121class AddedRulePendingTask(Event):
122    def __init__(self, trace, data):
123        (rule, task) = data
124        self.rule = trace.rules[rule]
125        self.task = trace.tasks[task]
126
127class RuleScheduledForScanning(Event):
128    def __init__(self, trace, data):
129        (rule,) = data
130        self.rule = trace.rules[rule]
131
132class PausedInputRequestForRuleScan(Event):
133    def __init__(self, trace, data):
134        (rule,) = data
135        self.rule = trace.rules[rule]
136
137class ReadyingTaskInputRequest(Event):
138    def __init__(self, trace, data):
139        (task, rule) = data
140        self.task = trace.tasks[task]
141        self.rule = trace.rules[rule]
142
143class CompletedTaskInputRequest(Event):
144    def __init__(self, trace, data):
145        (task, rule) = data
146        self.task = trace.tasks[task]
147        self.rule = trace.rules[rule]
148
149class UpdatedTaskWaitCount(Event):
150    def __init__(self, trace, data):
151        (task, count) = data
152        self.task = trace.tasks[task]
153        self.count = count
154
155class RuleScanningDeferredOnInput(Event):
156    def __init__(self, trace, data):
157        (rule, inputRule) = data
158        self.rule = trace.rules[rule]
159        self.inputRule = trace.rules[inputRule]
160
161class RuleScanningDeferredOnTask(Event):
162    def __init__(self, trace, data):
163        (rule, inputTask) = data
164        self.rule = trace.rules[rule]
165        self.inputTask = trace.tasks[inputTask]
166
167class RuleScanningNextInput(Event):
168    def __init__(self, trace, data):
169        (rule, inputRule) = data
170        self.rule = trace.rules[rule]
171        self.inputRule = trace.rules[inputRule]
172
173class UnblockedTask(Event):
174    def __init__(self, trace, data):
175        (task,) = data
176        self.task = trace.tasks[task]
177
178class ReadiedTask(Event):
179    def __init__(self, trace, data):
180        (task, rule) = data
181        self.task = trace.tasks[task]
182        assert(self.task.rule is trace.rules[rule])
183
184class FinishedTask(Event):
185    def __init__(self, trace, data):
186        (task, rule, effect) = data
187        self.task = trace.tasks[task]
188        assert(self.task.rule is trace.rules[rule])
189        self.effect = effect
190
191def _create_rule(trace, data):
192    rule = Rule(data)
193    trace.rules[rule.name] = rule
194
195def _create_task(trace, data):
196    task = Task(data)
197    trace.tasks[task.name] = task
198
199_event_handlers = {
200    "new-rule": _create_rule,
201    "new-task": _create_task,
202
203    "build-started": BuildStarted,
204    "build-ended": BuildEnded,
205    "handling-build-input-request": HandlingBuildInputRequest,
206    "checking-rule-needs-to-run": CheckingRuleNeedsToRun,
207    "rule-needs-to-run": RuleNeedsToRun,
208    "rule-does-not-need-to-run": RuleDoesNotNeedToRun,
209    "created-task-for-rule": CreatedTaskForRule,
210    "handling-task-input-request": HandlingTaskInputRequest,
211    "added-rule-pending-task": AddedRulePendingTask,
212    "rule-scheduled-for-scanning": RuleScheduledForScanning,
213    "paused-input-request-for-rule-scan": RuleScheduledForScanning,
214    "readying-task-input-request": ReadyingTaskInputRequest,
215    "completed-task-input-request": CompletedTaskInputRequest,
216    "updated-task-wait-count": UpdatedTaskWaitCount,
217    "rule-scanning-deferred-on-input": RuleScanningDeferredOnInput,
218    "rule-scanning-deferred-on-task": RuleScanningDeferredOnTask,
219    "rule-scanning-next-input": RuleScanningNextInput,
220    "unblocked-task": UnblockedTask,
221    "readied-task": ReadiedTask,
222    "finished-task": FinishedTask,
223}
224