blob: 615a7aed1501eb2f5a348b6858e898e4c4a74c9f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/usr/bin/env python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# Copyright (C) 2014 Alex Damian
6#
7# This file re-uses code spread throughout other Bitbake source files.
8# As such, all other copyrights belong to their own right holders.
9#
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License version 2 as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License along
21# with this program; if not, write to the Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24
25# This command takes a filename as a single parameter. The filename is read
26# as a build eventlog, and the ToasterUI is used to process events in the file
27# and log data in the database
28
29from __future__ import print_function
30import os
31import sys, logging
32
33# mangle syspath to allow easy import of modules
34sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
35 'lib'))
36
37
38import bb.cooker
39from bb.ui import toasterui
40import sys
41import logging
42
43import json, pickle
44
45
46class FileReadEventsServerConnection():
47 """ Emulates a connection to a bitbake server that feeds
48 events coming actually read from a saved log file.
49 """
50
51 class MockConnection():
52 """ fill-in for the proxy to the server. we just return generic data
53 """
54 def __init__(self, sc):
55 self._sc = sc
56
57 def runCommand(self, commandArray):
58 """ emulates running a command on the server; only read-only commands are accepted """
59 command_name = commandArray[0]
60
61 if command_name == "getVariable":
62 if commandArray[1] in self._sc._variables:
63 return (self._sc._variables[commandArray[1]]['v'], None)
64 return (None, "Missing variable")
65
66 elif command_name == "getAllKeysWithFlags":
67 dump = {}
68 flaglist = commandArray[1]
69 for k in self._sc._variables.keys():
70 try:
71 if not k.startswith("__"):
72 v = self._sc._variables[k]['v']
73 dump[k] = {
74 'v' : v ,
75 'history' : self._sc._variables[k]['history'],
76 }
77 for d in flaglist:
78 dump[k][d] = self._sc._variables[k][d]
79 except Exception as e:
80 print(e)
81 return (dump, None)
82 else:
83 raise Exception("Command %s not implemented" % commandArray[0])
84
85 def terminateServer(self):
86 """ do not do anything """
87 pass
88
89
90
91 class EventReader():
92 def __init__(self, sc):
93 self._sc = sc
94 self.firstraise = 0
95
96 def _create_event(self, line):
97 def _import_class(name):
98 assert len(name) > 0
99 assert "." in name, name
100
101 components = name.strip().split(".")
102 modulename = ".".join(components[:-1])
103 moduleklass = components[-1]
104
105 module = __import__(modulename, fromlist=[str(moduleklass)])
106 return getattr(module, moduleklass)
107
108 # we build a toaster event out of current event log line
109 try:
110 event_data = json.loads(line.strip())
111 event_class = _import_class(event_data['class'])
112 event_object = pickle.loads(json.loads(event_data['vars']))
113 except ValueError as e:
114 print("Failed loading ", line)
115 raise e
116
117 if not isinstance(event_object, event_class):
118 raise Exception("Error loading objects %s class %s ", event_object, event_class)
119
120 return event_object
121
122 def waitEvent(self, timeout):
123
124 nextline = self._sc._eventfile.readline()
125 if len(nextline) == 0:
126 # the build data ended, while toasterui still waits for events.
127 # this happens when the server was abruptly stopped, so we simulate this
128 self.firstraise += 1
129 if self.firstraise == 1:
130 raise KeyboardInterrupt()
131 else:
132 return None
133 else:
134 self._sc.lineno += 1
135 return self._create_event(nextline)
136
137
138 def _readVariables(self, variableline):
139 self._variables = json.loads(variableline.strip())['allvariables']
140
141
142 def __init__(self, file_name):
143 self.connection = FileReadEventsServerConnection.MockConnection(self)
144 self._eventfile = open(file_name, "r")
145
146 # we expect to have the variable dump at the start of the file
147 self.lineno = 1
148 self._readVariables(self._eventfile.readline())
149
150 self.events = FileReadEventsServerConnection.EventReader(self)
151
152
153
154
155
156class MockConfigParameters():
157 """ stand-in for cookerdata.ConfigParameters; as we don't really config a cooker, this
158 serves just to supply needed interfaces for the toaster ui to work """
159 def __init__(self):
160 self.observe_only = True # we can only read files
161
162
163# run toaster ui on our mock bitbake class
164if __name__ == "__main__":
165 if len(sys.argv) < 2:
166 print("Usage: %s event.log " % sys.argv[0])
167 sys.exit(1)
168
169 file_name = sys.argv[-1]
170 mock_connection = FileReadEventsServerConnection(file_name)
171 configParams = MockConfigParameters()
172
173 # run the main program and set exit code to the returned value
174 sys.exit(toasterui.main(mock_connection.connection, mock_connection.events, configParams))