1 def tinder_http_post(server, selector, content_type, body):
6 h = httplib.HTTP(server)
7 h.putrequest('POST', selector)
8 h.putheader('content-type', content_type)
9 h.putheader('content-length', str(len(body)))
12 errcode, errmsg, headers = h.getreply()
13 #print errcode, errmsg, headers
14 return (errcode,errmsg, headers, h.file)
16 print "Error sending the report!"
21 return (-1, "unknown", "unknown", None)
23 def tinder_form_data(bound, dict, log):
25 # for each key in the dictionary
27 output.append( "--" + bound )
28 output.append( 'Content-Disposition: form-data; name="%s"' % name )
30 output.append( dict[name] )
32 output.append( "--" + bound )
33 output.append( 'Content-Disposition: form-data; name="log"; filename="log.txt"' )
36 output.append( '--' + bound + '--' )
39 return "\r\n".join(output)
41 def tinder_time_string():
43 Return the time as GMT
47 def tinder_format_http_post(d,status,log):
49 Format the Tinderbox HTTP post with the data needed
50 for the tinderbox to be happy.
53 from bb import data, build
56 # the variables we will need to send on this form post
58 "tree" : data.getVar('TINDER_TREE', d, True),
59 "machine_name" : data.getVar('TINDER_MACHINE', d, True),
61 "os_version" : os.uname()[2],
63 "clobber" : data.getVar('TINDER_CLOBBER', d, True)
66 # optionally add the status
68 variables["status"] = str(status)
70 # try to load the machine id
71 # we only need on build_status.pl but sending it
72 # always does not hurt
74 f = file(data.getVar('TMPDIR',d,True)+'/tinder-machine.id', 'r')
76 variables['machine_id'] = id
80 # the boundary we will need
81 boundary = "----------------------------------%d" % int(random.random()*1000000000000)
84 body = tinder_form_data( boundary, variables, log )
86 return ("multipart/form-data; boundary=%s" % boundary),body
89 def tinder_build_start(d):
91 Inform the tinderbox that a build is starting. We do this
92 by posting our name and tree to the build_start.pl script
97 # get the body and type
98 content_type, body = tinder_format_http_post(d,None,None)
99 server = data.getVar('TINDER_HOST', d, True )
100 url = data.getVar('TINDER_URL', d, True )
102 selector = url + "/xml/build_start.pl"
104 #print "selector %s and url %s" % (selector, url)
107 errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
108 #print errcode, errmsg, headers
109 report = h_file.read()
111 # now let us find the machine id that was assigned to us
112 search = "<machine id='"
113 report = report[report.find(search)+len(search):]
114 report = report[0:report.find("'")]
117 bb.note("Machine ID assigned by tinderbox: %s" % report )
119 # now we will need to save the machine number
120 # we will override any previous numbers
121 f = file(data.getVar('TMPDIR', d, True)+"/tinder-machine.id", 'w')
125 def tinder_send_http(d, status, _log):
127 Send this log as build status
132 # get the body and type
133 server = data.getVar('TINDER_HOST', d, True )
134 url = data.getVar('TINDER_URL', d, True )
136 selector = url + "/xml/build_status.pl"
138 # now post it - in chunks of 10.000 charachters
140 while len(new_log) > 0:
141 content_type, body = tinder_format_http_post(d,status,new_log[0:18000])
142 errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
143 #print errcode, errmsg, headers
145 new_log = new_log[18000:]
148 def tinder_print_info(d):
150 Print the TinderBox Info
151 Including informations of the BaseSystem and the Tree
159 time = tinder_time_string()
161 version = os.uname()[2]
162 url = data.getVar( 'TINDER_URL' , d, True )
163 tree = data.getVar( 'TINDER_TREE', d, True )
164 branch = data.getVar( 'TINDER_BRANCH', d, True )
165 srcdate = data.getVar( 'SRCDATE', d, True )
166 machine = data.getVar( 'MACHINE', d, True )
167 distro = data.getVar( 'DISTRO', d, True )
168 bbfiles = data.getVar( 'BBFILES', d, True )
169 tarch = data.getVar( 'TARGET_ARCH', d, True )
170 fpu = data.getVar( 'TARGET_FPU', d, True )
171 oerev = data.getVar( 'OE_REVISION', d, True ) or "unknown"
173 # there is a bug with tipple quoted strings
174 # i will work around but will fix the original
177 output.append("== Tinderbox Info" )
178 output.append("Time: %(time)s" )
179 output.append("OS: %(ops)s" )
180 output.append("%(version)s" )
181 output.append("Compiler: gcc" )
182 output.append("Tinderbox Client: 0.1" )
183 output.append("Tinderbox Client Last Modified: yesterday" )
184 output.append("Tinderbox Protocol: 0.1" )
185 output.append("URL: %(url)s" )
186 output.append("Tree: %(tree)s" )
187 output.append("Config:" )
188 output.append("branch = '%(branch)s'" )
189 output.append("TARGET_ARCH = '%(tarch)s'" )
190 output.append("TARGET_FPU = '%(fpu)s'" )
191 output.append("SRCDATE = '%(srcdate)s'" )
192 output.append("MACHINE = '%(machine)s'" )
193 output.append("DISTRO = '%(distro)s'" )
194 output.append("BBFILES = '%(bbfiles)s'" )
195 output.append("OEREV = '%(oerev)s'" )
196 output.append("== End Tinderbox Client Info" )
198 # now create the real output
199 return "\n".join(output) % vars()
202 def tinder_print_env():
204 Print the environment variables of this build
209 time_start = tinder_time_string()
210 time_end = tinder_time_string()
212 # build the environment
214 for var in os.environ:
215 env += "%s=%s\n" % (var, os.environ[var])
218 output.append( "---> TINDERBOX RUNNING env %(time_start)s" )
220 output.append( "<--- TINDERBOX FINISHED (SUCCESS) %(time_end)s" )
222 return "\n".join(output) % vars()
224 def tinder_tinder_start(d, event):
226 PRINT the configuration of this build
229 time_start = tinder_time_string()
230 config = tinder_print_info(d)
231 #env = tinder_print_env()
232 time_end = tinder_time_string()
233 packages = " ".join( event.getPkgs() )
236 output.append( "---> TINDERBOX PRINTING CONFIGURATION %(time_start)s" )
237 output.append( config )
238 #output.append( env )
239 output.append( "<--- TINDERBOX FINISHED PRINTING CONFIGURATION %(time_end)s" )
240 output.append( "---> TINDERBOX BUILDING '%(packages)s'" )
241 output.append( "<--- TINDERBOX STARTING BUILD NOW" )
245 return "\n".join(output) % vars()
247 def tinder_do_tinder_report(event):
249 Report to the tinderbox:
250 On the BuildStart we will inform the box directly
251 On the other events we will write to the TINDER_LOG and
252 when the Task is finished we will send the report.
254 The above is not yet fully implemented. Currently we send
255 information immediately. The caching/queuing needs to be
256 implemented. Also sending more or less information is not
259 We have two temporary files stored in the TMP directory. One file
260 contains the assigned machine id for the tinderclient. This id gets
261 assigned when we connect the box and start the build process the second
262 file is used to workaround an EventHandler limitation. If BitBake is ran
263 with the continue option we want the Build to fail even if we get the
264 BuildCompleted Event. In this case we have to look up the status and
265 send it instead of 100/success.
267 from bb.event import getName
268 from bb import data, mkdirhier, build
272 name = getName(event)
275 # Check what we need to do Build* shows we start or are done
276 if name == "BuildStarted":
277 tinder_build_start(event.data)
278 log = tinder_tinder_start(event.data,event)
281 # truncate the tinder log file
282 f = file(data.getVar('TINDER_LOG', event.data, True), 'w')
289 # write a status to the file. This is needed for the -k option
291 g = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
297 # Append the Task-Log (compile,configure...) to the log file
298 # we will send to the server
299 if name == "TaskSucceeded" or name == "TaskFailed":
300 log_file = glob.glob("%s/log.%s.*" % (data.getVar('T', event.data, True), event.task))
302 if len(log_file) != 0:
303 to_file = data.getVar('TINDER_LOG', event.data, True)
304 log += "".join(open(log_file[0], 'r').readlines())
306 # set the right 'HEADER'/Summary for the TinderBox
307 if name == "TaskStarted":
308 log += "---> TINDERBOX Task %s started\n" % event.task
309 elif name == "TaskSucceeded":
310 log += "<--- TINDERBOX Task %s done (SUCCESS)\n" % event.task
311 elif name == "TaskFailed":
312 log += "<--- TINDERBOX Task %s failed (FAILURE)\n" % event.task
313 elif name == "PkgStarted":
314 log += "---> TINDERBOX Package %s started\n" % data.getVar('PF', event.data, True)
315 elif name == "PkgSucceeded":
316 log += "<--- TINDERBOX Package %s done (SUCCESS)\n" % data.getVar('PF', event.data, True)
317 elif name == "PkgFailed":
318 if not data.getVar('TINDER_AUTOBUILD', event.data, True) == "0":
319 build.exec_task('do_clean', event.data)
320 log += "<--- TINDERBOX Package %s failed (FAILURE)\n" % data.getVar('PF', event.data, True)
322 # remember the failure for the -k case
323 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
325 elif name == "BuildCompleted":
326 log += "Build Completed\n"
328 # Check if we have a old status...
330 h = file(data.getVar('TMPDIR',event.data,True)+'/tinder-status', 'r')
331 status = int(h.read())
335 elif name == "MultipleProviders":
336 log += "---> TINDERBOX Multiple Providers\n"
337 log += "multiple providers are available (%s);\n" % ", ".join(event.getCandidates())
338 log += "consider defining PREFERRED_PROVIDER_%s\n" % event.getItem()
339 log += "is runtime: %d\n" % event.isRuntime()
340 log += "<--- TINDERBOX Multiple Providers\n"
341 elif name == "NoProvider":
342 log += "Error: No Provider for: %s\n" % event.getItem()
343 log += "Error:Was Runtime: %d\n" % event.isRuntime()
345 # remember the failure for the -k case
346 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
353 # for now we will use the http post method as it is the only one
354 log_post_method = tinder_send_http
355 log_post_method(event.data, status, log)
358 # we want to be an event handler
359 addhandler tinderclient_eventhandler
360 python tinderclient_eventhandler() {
361 from bb import note, error, data
362 from bb.event import NotHandled
363 do_tinder_report = data.getVar('TINDER_REPORT', e.data, True)
364 if do_tinder_report and do_tinder_report == "1":
365 tinder_do_tinder_report(e)