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