1 def tinder_http_post(d, server, selector, content_type, body):
7 proxy = data.getVar('HTTP_PROXY', d, True )
9 if (proxy.endswith('/')):
11 if (proxy.startswith('http://')):
13 h = httplib.HTTP(proxy)
14 h.putrequest('POST', 'http://%s%s' % (server, selector))
16 h = httplib.HTTP(server)
17 h.putrequest('POST', selector)
18 h.putheader('content-type', content_type)
19 h.putheader('content-length', str(len(body)))
22 errcode, errmsg, headers = h.getreply()
23 #print errcode, errmsg, headers
24 return (errcode,errmsg, headers, h.file)
26 print "Error sending the report! ", e
31 return (-1, "unknown", "unknown", None)
33 def tinder_form_data(bound, dict, log):
35 # for each key in the dictionary
38 output.append( "--" + bound )
39 output.append( 'Content-Disposition: form-data; name="%s"' % name )
41 output.append( dict[name] )
43 output.append( "--" + bound )
44 output.append( 'Content-Disposition: form-data; name="log"; filename="log.txt"' )
47 output.append( '--' + bound + '--' )
50 return "\r\n".join(output)
52 def tinder_time_string():
54 Return the time as GMT
58 def tinder_format_http_post(d,status,log):
60 Format the Tinderbox HTTP post with the data needed
61 for the tinderbox to be happy.
64 from bb import data, build
67 # the variables we will need to send on this form post
69 "tree" : data.getVar('TINDER_TREE', d, True),
70 "machine_name" : data.getVar('TINDER_MACHINE', d, True),
72 "os_version" : os.uname()[2],
74 "clobber" : data.getVar('TINDER_CLOBBER', d, True) or "0",
75 "srcdate" : data.getVar('SRCDATE', d, True),
76 "PN" : data.getVar('PN', d, True),
77 "PV" : data.getVar('PV', d, True),
78 "PR" : data.getVar('PR', d, True),
79 "FILE" : data.getVar('FILE', d, True) or "N/A",
80 "TARGETARCH" : data.getVar('TARGET_ARCH', d, True),
81 "TARGETFPU" : data.getVar('TARGET_FPU', d, True) or "Unknown",
82 "TARGETOS" : data.getVar('TARGET_OS', d, True) or "Unknown",
83 "MACHINE" : data.getVar('MACHINE', d, True) or "Unknown",
84 "DISTRO" : data.getVar('DISTRO', d, True) or "Unknown",
85 "zecke-rocks" : "sure",
88 # optionally add the status
90 variables["status"] = str(status)
92 # try to load the machine id
93 # we only need on build_status.pl but sending it
94 # always does not hurt
96 f = file(data.getVar('TMPDIR',d,True)+'/tinder-machine.id', 'r')
98 variables['machine_id'] = id
102 # the boundary we will need
103 boundary = "----------------------------------%d" % int(random.random()*1000000000000)
105 # now format the body
106 body = tinder_form_data( boundary, variables, log )
108 return ("multipart/form-data; boundary=%s" % boundary),body
111 def tinder_build_start(d):
113 Inform the tinderbox that a build is starting. We do this
114 by posting our name and tree to the build_start.pl script
119 # get the body and type
120 content_type, body = tinder_format_http_post(d,None,None)
121 server = data.getVar('TINDER_HOST', d, True )
122 url = data.getVar('TINDER_URL', d, True )
124 selector = url + "/xml/build_start.pl"
126 #print "selector %s and url %s" % (selector, url)
129 errcode, errmsg, headers, h_file = tinder_http_post(d,server,selector,content_type, body)
130 #print errcode, errmsg, headers
131 report = h_file.read()
133 # now let us find the machine id that was assigned to us
134 search = "<machine id='"
135 report = report[report.find(search)+len(search):]
136 report = report[0:report.find("'")]
139 bb.note("Machine ID assigned by tinderbox: %s" % report )
141 # now we will need to save the machine number
142 # we will override any previous numbers
143 f = file(data.getVar('TMPDIR', d, True)+"/tinder-machine.id", 'w')
147 def tinder_send_http(d, status, _log):
149 Send this log as build status
154 # get the body and type
155 server = data.getVar('TINDER_HOST', d, True )
156 url = data.getVar('TINDER_URL', d, True )
158 selector = url + "/xml/build_status.pl"
160 # now post it - in chunks of 10.000 charachters
162 while len(new_log) > 0:
163 content_type, body = tinder_format_http_post(d,status,new_log[0:18000])
164 errcode, errmsg, headers, h_file = tinder_http_post(d,server,selector,content_type, body)
165 #print errcode, errmsg, headers
167 new_log = new_log[18000:]
170 def tinder_print_info(d):
172 Print the TinderBox Info
173 Including informations of the BaseSystem and the Tree
181 time = tinder_time_string()
183 version = os.uname()[2]
184 url = data.getVar( 'TINDER_URL' , d, True )
185 tree = data.getVar( 'TINDER_TREE', d, True )
186 branch = data.getVar( 'TINDER_BRANCH', d, True )
187 srcdate = data.getVar( 'SRCDATE', d, True )
188 machine = data.getVar( 'MACHINE', d, True )
189 distro = data.getVar( 'DISTRO', d, True )
190 bbfiles = data.getVar( 'BBFILES', d, True )
191 tarch = data.getVar( 'TARGET_ARCH', d, True )
192 fpu = data.getVar( 'TARGET_FPU', d, True )
193 oerev = data.getVar( 'OE_REVISION', d, True ) or "unknown"
195 # there is a bug with tipple quoted strings
196 # i will work around but will fix the original
199 output.append("== Tinderbox Info" )
200 output.append("Time: %(time)s" )
201 output.append("OS: %(ops)s" )
202 output.append("%(version)s" )
203 output.append("Compiler: gcc" )
204 output.append("Tinderbox Client: 0.1" )
205 output.append("Tinderbox Client Last Modified: yesterday" )
206 output.append("Tinderbox Protocol: 0.1" )
207 output.append("URL: %(url)s" )
208 output.append("Tree: %(tree)s" )
209 output.append("Config:" )
210 output.append("branch = '%(branch)s'" )
211 output.append("TARGET_ARCH = '%(tarch)s'" )
212 output.append("TARGET_FPU = '%(fpu)s'" )
213 output.append("SRCDATE = '%(srcdate)s'" )
214 output.append("MACHINE = '%(machine)s'" )
215 output.append("DISTRO = '%(distro)s'" )
216 output.append("BBFILES = '%(bbfiles)s'" )
217 output.append("OEREV = '%(oerev)s'" )
218 output.append("== End Tinderbox Client Info" )
220 # now create the real output
221 return "\n".join(output) % vars()
224 def tinder_print_env():
226 Print the environment variables of this build
231 time_start = tinder_time_string()
232 time_end = tinder_time_string()
234 # build the environment
236 for var in os.environ:
237 env += "%s=%s\n" % (var, os.environ[var])
240 output.append( "---> TINDERBOX RUNNING env %(time_start)s" )
242 output.append( "<--- TINDERBOX FINISHED (SUCCESS) %(time_end)s" )
244 return "\n".join(output) % vars()
246 def tinder_tinder_start(d, event):
248 PRINT the configuration of this build
251 time_start = tinder_time_string()
252 config = tinder_print_info(d)
253 #env = tinder_print_env()
254 time_end = tinder_time_string()
255 packages = " ".join( event.getPkgs() )
258 output.append( "---> TINDERBOX PRINTING CONFIGURATION %(time_start)s" )
259 output.append( config )
260 #output.append( env )
261 output.append( "<--- TINDERBOX FINISHED PRINTING CONFIGURATION %(time_end)s" )
262 output.append( "---> TINDERBOX BUILDING '%(packages)s'" )
263 output.append( "<--- TINDERBOX STARTING BUILD NOW" )
267 return "\n".join(output) % vars()
269 def tinder_do_tinder_report(event):
271 Report to the tinderbox:
272 On the BuildStart we will inform the box directly
273 On the other events we will write to the TINDER_LOG and
274 when the Task is finished we will send the report.
276 The above is not yet fully implemented. Currently we send
277 information immediately. The caching/queuing needs to be
278 implemented. Also sending more or less information is not
281 We have two temporary files stored in the TMP directory. One file
282 contains the assigned machine id for the tinderclient. This id gets
283 assigned when we connect the box and start the build process the second
284 file is used to workaround an EventHandler limitation. If BitBake is ran
285 with the continue option we want the Build to fail even if we get the
286 BuildCompleted Event. In this case we have to look up the status and
287 send it instead of 100/success.
289 from bb.event import getName
290 from bb import data, mkdirhier, build
294 name = getName(event)
297 # Check what we need to do Build* shows we start or are done
298 if name == "BuildStarted":
299 tinder_build_start(event.data)
300 log = tinder_tinder_start(event.data,event)
303 # truncate the tinder log file
304 f = file(data.getVar('TINDER_LOG', event.data, True), 'w')
311 # write a status to the file. This is needed for the -k option
313 g = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
319 # Append the Task-Log (compile,configure...) to the log file
320 # we will send to the server
321 if name == "TaskSucceeded" or name == "TaskFailed":
322 log_file = glob.glob("%s/log.%s.*" % (data.getVar('T', event.data, True), event.task))
324 if len(log_file) != 0:
325 to_file = data.getVar('TINDER_LOG', event.data, True)
326 log += "".join(open(log_file[0], 'r').readlines())
328 # set the right 'HEADER'/Summary for the TinderBox
329 if name == "TaskStarted":
330 log += "---> TINDERBOX Task %s started\n" % event.task
331 elif name == "TaskSucceeded":
332 log += "<--- TINDERBOX Task %s done (SUCCESS)\n" % event.task
333 elif name == "TaskFailed":
334 log += "<--- TINDERBOX Task %s failed (FAILURE)\n" % event.task
335 elif name == "PkgStarted":
336 log += "---> TINDERBOX Package %s started\n" % data.getVar('PF', event.data, True)
337 elif name == "PkgSucceeded":
338 log += "<--- TINDERBOX Package %s done (SUCCESS)\n" % data.getVar('PF', event.data, True)
339 elif name == "PkgFailed":
340 if not data.getVar('TINDER_AUTOBUILD', event.data, True) == "0":
341 build.exec_func('do_clean', event.data)
342 log += "<--- TINDERBOX Package %s failed (FAILURE)\n" % data.getVar('PF', event.data, True)
344 # remember the failure for the -k case
345 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
347 elif name == "BuildCompleted":
348 log += "Build Completed\n"
350 # Check if we have a old status...
352 h = file(data.getVar('TMPDIR',event.data,True)+'/tinder-status', 'r')
353 status = int(h.read())
357 elif name == "MultipleProviders":
358 log += "---> TINDERBOX Multiple Providers\n"
359 log += "multiple providers are available (%s);\n" % ", ".join(event.getCandidates())
360 log += "consider defining PREFERRED_PROVIDER_%s\n" % event.getItem()
361 log += "is runtime: %d\n" % event.isRuntime()
362 log += "<--- TINDERBOX Multiple Providers\n"
363 elif name == "NoProvider":
364 log += "Error: No Provider for: %s\n" % event.getItem()
365 log += "Error:Was Runtime: %d\n" % event.isRuntime()
367 # remember the failure for the -k case
368 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
375 # for now we will use the http post method as it is the only one
376 log_post_method = tinder_send_http
377 log_post_method(event.data, status, log)
380 # we want to be an event handler
381 addhandler tinderclient_eventhandler
382 python tinderclient_eventhandler() {
383 from bb import note, error, data
384 from bb.event import NotHandled, getName
386 if e.data is None or getName(e) == "MsgNote":
389 do_tinder_report = data.getVar('TINDER_REPORT', e.data, True)
390 if do_tinder_report and do_tinder_report == "1":
391 tinder_do_tinder_report(e)