1 def tinder_http_post(d, server, selector, content_type, body):
6 proxy = data.getVar('HTTP_PROXY', d, True )
8 if (proxy.endswith('/')):
10 if (proxy.startswith('http://')):
12 h = httplib.HTTP(proxy)
13 h.putrequest('POST', 'http://%s%s' % (server, selector))
15 h = httplib.HTTP(server)
16 h.putrequest('POST', selector)
17 h.putheader('content-type', content_type)
18 h.putheader('content-length', str(len(body)))
21 errcode, errmsg, headers = h.getreply()
22 #print errcode, errmsg, headers
23 return (errcode,errmsg, headers, h.file)
25 print "Error sending the report! ", e
30 return (-1, "unknown", "unknown", None)
32 def tinder_form_data(bound, dict, log):
34 # for each key in the dictionary
37 output.append( "--" + bound )
38 output.append( 'Content-Disposition: form-data; name="%s"' % name )
40 output.append( dict[name] )
42 output.append( "--" + bound )
43 output.append( 'Content-Disposition: form-data; name="log"; filename="log.txt"' )
46 output.append( '--' + bound + '--' )
49 return "\r\n".join(output)
51 def tinder_time_string():
53 Return the time as GMT
57 def tinder_format_http_post(d,status,log):
59 Format the Tinderbox HTTP post with the data needed
60 for the tinderbox to be happy.
65 # the variables we will need to send on this form post
67 "tree" : data.getVar('TINDER_TREE', d, True),
68 "machine_name" : data.getVar('TINDER_MACHINE', d, True),
70 "os_version" : os.uname()[2],
72 "clobber" : data.getVar('TINDER_CLOBBER', d, True) or "0",
73 "srcdate" : data.getVar('SRCDATE', d, True),
74 "PN" : data.getVar('PN', d, True),
75 "PV" : data.getVar('PV', d, True),
76 "PR" : data.getVar('PR', d, True),
77 "FILE" : data.getVar('FILE', d, True) or "N/A",
78 "TARGETARCH" : data.getVar('TARGET_ARCH', d, True),
79 "TARGETFPU" : data.getVar('TARGET_FPU', d, True) or "Unknown",
80 "TARGETOS" : data.getVar('TARGET_OS', d, True) or "Unknown",
81 "MACHINE" : data.getVar('MACHINE', d, True) or "Unknown",
82 "DISTRO" : data.getVar('DISTRO', d, True) or "Unknown",
85 # optionally add the status
87 variables["status"] = str(status)
89 # try to load the machine id
90 # we only need on build_status.pl but sending it
91 # always does not hurt
93 f = file(data.getVar('TMPDIR',d,True)+'/tinder-machine.id', 'r')
95 variables['machine_id'] = id
99 # the boundary we will need
100 boundary = "----------------------------------%d" % int(random.random()*1000000000000)
102 # now format the body
103 body = tinder_form_data( boundary, variables, log )
105 return ("multipart/form-data; boundary=%s" % boundary),body
108 def tinder_build_start(d):
110 Inform the tinderbox that a build is starting. We do this
111 by posting our name and tree to the build_start.pl script
116 # get the body and type
117 content_type, body = tinder_format_http_post(d,None,None)
118 server = data.getVar('TINDER_HOST', d, True )
119 url = data.getVar('TINDER_URL', d, True )
121 selector = url + "/xml/build_start.pl"
123 #print "selector %s and url %s" % (selector, url)
126 errcode, errmsg, headers, h_file = tinder_http_post(d,server,selector,content_type, body)
127 #print errcode, errmsg, headers
128 report = h_file.read()
130 # now let us find the machine id that was assigned to us
131 search = "<machine id='"
132 report = report[report.find(search)+len(search):]
133 report = report[0:report.find("'")]
136 bb.note("Machine ID assigned by tinderbox: %s" % report )
138 # now we will need to save the machine number
139 # we will override any previous numbers
140 f = file(data.getVar('TMPDIR', d, True)+"/tinder-machine.id", 'w')
144 def tinder_send_http(d, status, _log):
146 Send this log as build status
151 # get the body and type
152 server = data.getVar('TINDER_HOST', d, True )
153 url = data.getVar('TINDER_URL', d, True )
155 selector = url + "/xml/build_status.pl"
157 # now post it - in chunks of 10.000 charachters
159 while len(new_log) > 0:
160 content_type, body = tinder_format_http_post(d,status,new_log[0:18000])
161 errcode, errmsg, headers, h_file = tinder_http_post(d,server,selector,content_type, body)
162 #print errcode, errmsg, headers
164 new_log = new_log[18000:]
167 def tinder_print_info(d):
169 Print the TinderBox Info
170 Including informations of the BaseSystem and the Tree
178 time = tinder_time_string()
180 version = os.uname()[2]
181 url = data.getVar( 'TINDER_URL' , d, True )
182 tree = data.getVar( 'TINDER_TREE', d, True )
183 branch = data.getVar( 'TINDER_BRANCH', d, True )
184 srcdate = data.getVar( 'SRCDATE', d, True )
185 machine = data.getVar( 'MACHINE', d, True )
186 distro = data.getVar( 'DISTRO', d, True )
187 bbfiles = data.getVar( 'BBFILES', d, True )
188 tarch = data.getVar( 'TARGET_ARCH', d, True )
189 fpu = data.getVar( 'TARGET_FPU', d, True )
190 oerev = data.getVar( 'OE_REVISION', d, True ) or "unknown"
192 # there is a bug with tipple quoted strings
193 # i will work around but will fix the original
196 output.append("== Tinderbox Info" )
197 output.append("Time: %(time)s" )
198 output.append("OS: %(ops)s" )
199 output.append("%(version)s" )
200 output.append("Compiler: gcc" )
201 output.append("Tinderbox Client: 0.1" )
202 output.append("Tinderbox Client Last Modified: yesterday" )
203 output.append("Tinderbox Protocol: 0.1" )
204 output.append("URL: %(url)s" )
205 output.append("Tree: %(tree)s" )
206 output.append("Config:" )
207 output.append("branch = '%(branch)s'" )
208 output.append("TARGET_ARCH = '%(tarch)s'" )
209 output.append("TARGET_FPU = '%(fpu)s'" )
210 output.append("SRCDATE = '%(srcdate)s'" )
211 output.append("MACHINE = '%(machine)s'" )
212 output.append("DISTRO = '%(distro)s'" )
213 output.append("BBFILES = '%(bbfiles)s'" )
214 output.append("OEREV = '%(oerev)s'" )
215 output.append("== End Tinderbox Client Info" )
217 # now create the real output
218 return "\n".join(output) % vars()
221 def tinder_print_env():
223 Print the environment variables of this build
228 time_start = tinder_time_string()
229 time_end = tinder_time_string()
231 # build the environment
233 for var in os.environ:
234 env += "%s=%s\n" % (var, os.environ[var])
237 output.append( "---> TINDERBOX RUNNING env %(time_start)s" )
239 output.append( "<--- TINDERBOX FINISHED (SUCCESS) %(time_end)s" )
241 return "\n".join(output) % vars()
243 def tinder_tinder_start(d, event):
245 PRINT the configuration of this build
248 time_start = tinder_time_string()
249 config = tinder_print_info(d)
250 #env = tinder_print_env()
251 time_end = tinder_time_string()
252 packages = " ".join( event.getPkgs() )
255 output.append( "---> TINDERBOX PRINTING CONFIGURATION %(time_start)s" )
256 output.append( config )
257 #output.append( env )
258 output.append( "<--- TINDERBOX FINISHED PRINTING CONFIGURATION %(time_end)s" )
259 output.append( "---> TINDERBOX BUILDING '%(packages)s'" )
260 output.append( "<--- TINDERBOX STARTING BUILD NOW" )
264 return "\n".join(output) % vars()
266 def tinder_do_tinder_report(event):
268 Report to the tinderbox:
269 On the BuildStart we will inform the box directly
270 On the other events we will write to the TINDER_LOG and
271 when the Task is finished we will send the report.
273 The above is not yet fully implemented. Currently we send
274 information immediately. The caching/queuing needs to be
275 implemented. Also sending more or less information is not
278 We have two temporary files stored in the TMP directory. One file
279 contains the assigned machine id for the tinderclient. This id gets
280 assigned when we connect the box and start the build process the second
281 file is used to workaround an EventHandler limitation. If BitBake is ran
282 with the continue option we want the Build to fail even if we get the
283 BuildCompleted Event. In this case we have to look up the status and
284 send it instead of 100/success.
286 from bb.event import getName
287 from bb import data, mkdirhier, build
291 name = getName(event)
294 # Check what we need to do Build* shows we start or are done
295 if name == "BuildStarted":
296 tinder_build_start(event.data)
297 log = tinder_tinder_start(event.data,event)
300 # truncate the tinder log file
301 f = file(data.getVar('TINDER_LOG', event.data, True), 'w')
308 # write a status to the file. This is needed for the -k option
310 g = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
316 # Append the Task-Log (compile,configure...) to the log file
317 # we will send to the server
318 if name == "TaskSucceeded" or name == "TaskFailed":
319 log_file = glob.glob("%s/log.%s.*" % (data.getVar('T', event.data, True), event.task))
321 if len(log_file) != 0:
322 to_file = data.getVar('TINDER_LOG', event.data, True)
323 log += "".join(open(log_file[0], 'r').readlines())
325 # set the right 'HEADER'/Summary for the TinderBox
326 if name == "TaskStarted":
327 log += "---> TINDERBOX Task %s started\n" % event.task
328 elif name == "TaskSucceeded":
329 log += "<--- TINDERBOX Task %s done (SUCCESS)\n" % event.task
330 elif name == "TaskFailed":
331 log += "<--- TINDERBOX Task %s failed (FAILURE)\n" % event.task
332 elif name == "PkgStarted":
333 log += "---> TINDERBOX Package %s started\n" % data.getVar('PF', event.data, True)
334 elif name == "PkgSucceeded":
335 log += "<--- TINDERBOX Package %s done (SUCCESS)\n" % data.getVar('PF', event.data, True)
336 elif name == "PkgFailed":
337 if not data.getVar('TINDER_AUTOBUILD', event.data, True) == "0":
338 build.exec_func('do_clean', event.data)
339 log += "<--- TINDERBOX Package %s failed (FAILURE)\n" % data.getVar('PF', event.data, True)
341 # remember the failure for the -k case
342 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
344 elif name == "BuildCompleted":
345 log += "Build Completed\n"
347 # Check if we have a old status...
349 h = file(data.getVar('TMPDIR',event.data,True)+'/tinder-status', 'r')
350 status = int(h.read())
354 elif name == "MultipleProviders":
355 log += "---> TINDERBOX Multiple Providers\n"
356 log += "multiple providers are available (%s);\n" % ", ".join(event.getCandidates())
357 log += "consider defining PREFERRED_PROVIDER_%s\n" % event.getItem()
358 log += "is runtime: %d\n" % event.isRuntime()
359 log += "<--- TINDERBOX Multiple Providers\n"
360 elif name == "NoProvider":
361 log += "Error: No Provider for: %s\n" % event.getItem()
362 log += "Error:Was Runtime: %d\n" % event.isRuntime()
364 # remember the failure for the -k case
365 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
372 # for now we will use the http post method as it is the only one
373 log_post_method = tinder_send_http
374 log_post_method(event.data, status, log)
377 # we want to be an event handler
378 addhandler tinderclient_eventhandler
379 python tinderclient_eventhandler() {
380 from bb import note, error, data
381 from bb.event import getName
383 if e.data is None or getName(e) == "MsgNote":
386 do_tinder_report = data.getVar('TINDER_REPORT', e.data, True)
387 if do_tinder_report and do_tinder_report == "1":
388 tinder_do_tinder_report(e)