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),
64 "srcdate" : data.getVar('SRCDATE', d, True),
65 "PN" : data.getVar('PN', d, True),
66 "PV" : data.getVar('PV', d, True),
67 "PR" : data.getVar('PR', d, True),
68 "FILE" : data.getVar('FILE', d, True) or "N/A",
69 "TARGETARCH" : data.getVar('TARGET_ARCH', d, True),
70 "TARGETFPU" : data.getVar('TARGET_FPU', d, True) or "Unknown",
71 "TARGETOS" : data.getVar('TARGET_OS', d, True) or "Unknown",
72 "MACHINE" : data.getVar('MACHINE', d, True) or "Unknown",
73 "DISTRO" : data.getVar('DISTRO', d, True) or "Unknown",
74 "zecke-rocks" : "sure",
77 # optionally add the status
79 variables["status"] = str(status)
81 # try to load the machine id
82 # we only need on build_status.pl but sending it
83 # always does not hurt
85 f = file(data.getVar('TMPDIR',d,True)+'/tinder-machine.id', 'r')
87 variables['machine_id'] = id
91 # the boundary we will need
92 boundary = "----------------------------------%d" % int(random.random()*1000000000000)
95 body = tinder_form_data( boundary, variables, log )
97 return ("multipart/form-data; boundary=%s" % boundary),body
100 def tinder_build_start(d):
102 Inform the tinderbox that a build is starting. We do this
103 by posting our name and tree to the build_start.pl script
108 # get the body and type
109 content_type, body = tinder_format_http_post(d,None,None)
110 server = data.getVar('TINDER_HOST', d, True )
111 url = data.getVar('TINDER_URL', d, True )
113 selector = url + "/xml/build_start.pl"
115 #print "selector %s and url %s" % (selector, url)
118 errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
119 #print errcode, errmsg, headers
120 report = h_file.read()
122 # now let us find the machine id that was assigned to us
123 search = "<machine id='"
124 report = report[report.find(search)+len(search):]
125 report = report[0:report.find("'")]
128 bb.note("Machine ID assigned by tinderbox: %s" % report )
130 # now we will need to save the machine number
131 # we will override any previous numbers
132 f = file(data.getVar('TMPDIR', d, True)+"/tinder-machine.id", 'w')
136 def tinder_send_http(d, status, _log):
138 Send this log as build status
143 # get the body and type
144 server = data.getVar('TINDER_HOST', d, True )
145 url = data.getVar('TINDER_URL', d, True )
147 selector = url + "/xml/build_status.pl"
149 # now post it - in chunks of 10.000 charachters
151 while len(new_log) > 0:
152 content_type, body = tinder_format_http_post(d,status,new_log[0:18000])
153 errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
154 #print errcode, errmsg, headers
156 new_log = new_log[18000:]
159 def tinder_print_info(d):
161 Print the TinderBox Info
162 Including informations of the BaseSystem and the Tree
170 time = tinder_time_string()
172 version = os.uname()[2]
173 url = data.getVar( 'TINDER_URL' , d, True )
174 tree = data.getVar( 'TINDER_TREE', d, True )
175 branch = data.getVar( 'TINDER_BRANCH', d, True )
176 srcdate = data.getVar( 'SRCDATE', d, True )
177 machine = data.getVar( 'MACHINE', d, True )
178 distro = data.getVar( 'DISTRO', d, True )
179 bbfiles = data.getVar( 'BBFILES', d, True )
180 tarch = data.getVar( 'TARGET_ARCH', d, True )
181 fpu = data.getVar( 'TARGET_FPU', d, True )
182 oerev = data.getVar( 'OE_REVISION', d, True ) or "unknown"
184 # there is a bug with tipple quoted strings
185 # i will work around but will fix the original
188 output.append("== Tinderbox Info" )
189 output.append("Time: %(time)s" )
190 output.append("OS: %(ops)s" )
191 output.append("%(version)s" )
192 output.append("Compiler: gcc" )
193 output.append("Tinderbox Client: 0.1" )
194 output.append("Tinderbox Client Last Modified: yesterday" )
195 output.append("Tinderbox Protocol: 0.1" )
196 output.append("URL: %(url)s" )
197 output.append("Tree: %(tree)s" )
198 output.append("Config:" )
199 output.append("branch = '%(branch)s'" )
200 output.append("TARGET_ARCH = '%(tarch)s'" )
201 output.append("TARGET_FPU = '%(fpu)s'" )
202 output.append("SRCDATE = '%(srcdate)s'" )
203 output.append("MACHINE = '%(machine)s'" )
204 output.append("DISTRO = '%(distro)s'" )
205 output.append("BBFILES = '%(bbfiles)s'" )
206 output.append("OEREV = '%(oerev)s'" )
207 output.append("== End Tinderbox Client Info" )
209 # now create the real output
210 return "\n".join(output) % vars()
213 def tinder_print_env():
215 Print the environment variables of this build
220 time_start = tinder_time_string()
221 time_end = tinder_time_string()
223 # build the environment
225 for var in os.environ:
226 env += "%s=%s\n" % (var, os.environ[var])
229 output.append( "---> TINDERBOX RUNNING env %(time_start)s" )
231 output.append( "<--- TINDERBOX FINISHED (SUCCESS) %(time_end)s" )
233 return "\n".join(output) % vars()
235 def tinder_tinder_start(d, event):
237 PRINT the configuration of this build
240 time_start = tinder_time_string()
241 config = tinder_print_info(d)
242 #env = tinder_print_env()
243 time_end = tinder_time_string()
244 packages = " ".join( event.getPkgs() )
247 output.append( "---> TINDERBOX PRINTING CONFIGURATION %(time_start)s" )
248 output.append( config )
249 #output.append( env )
250 output.append( "<--- TINDERBOX FINISHED PRINTING CONFIGURATION %(time_end)s" )
251 output.append( "---> TINDERBOX BUILDING '%(packages)s'" )
252 output.append( "<--- TINDERBOX STARTING BUILD NOW" )
256 return "\n".join(output) % vars()
258 def tinder_do_tinder_report(event):
260 Report to the tinderbox:
261 On the BuildStart we will inform the box directly
262 On the other events we will write to the TINDER_LOG and
263 when the Task is finished we will send the report.
265 The above is not yet fully implemented. Currently we send
266 information immediately. The caching/queuing needs to be
267 implemented. Also sending more or less information is not
270 We have two temporary files stored in the TMP directory. One file
271 contains the assigned machine id for the tinderclient. This id gets
272 assigned when we connect the box and start the build process the second
273 file is used to workaround an EventHandler limitation. If BitBake is ran
274 with the continue option we want the Build to fail even if we get the
275 BuildCompleted Event. In this case we have to look up the status and
276 send it instead of 100/success.
278 from bb.event import getName
279 from bb import data, mkdirhier, build
283 name = getName(event)
286 # Check what we need to do Build* shows we start or are done
287 if name == "BuildStarted":
288 tinder_build_start(event.data)
289 log = tinder_tinder_start(event.data,event)
292 # truncate the tinder log file
293 f = file(data.getVar('TINDER_LOG', event.data, True), 'w')
300 # write a status to the file. This is needed for the -k option
302 g = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
308 # Append the Task-Log (compile,configure...) to the log file
309 # we will send to the server
310 if name == "TaskSucceeded" or name == "TaskFailed":
311 log_file = glob.glob("%s/log.%s.*" % (data.getVar('T', event.data, True), event.task))
313 if len(log_file) != 0:
314 to_file = data.getVar('TINDER_LOG', event.data, True)
315 log += "".join(open(log_file[0], 'r').readlines())
317 # set the right 'HEADER'/Summary for the TinderBox
318 if name == "TaskStarted":
319 log += "---> TINDERBOX Task %s started\n" % event.task
320 elif name == "TaskSucceeded":
321 log += "<--- TINDERBOX Task %s done (SUCCESS)\n" % event.task
322 elif name == "TaskFailed":
323 log += "<--- TINDERBOX Task %s failed (FAILURE)\n" % event.task
324 elif name == "PkgStarted":
325 log += "---> TINDERBOX Package %s started\n" % data.getVar('PF', event.data, True)
326 elif name == "PkgSucceeded":
327 log += "<--- TINDERBOX Package %s done (SUCCESS)\n" % data.getVar('PF', event.data, True)
328 elif name == "PkgFailed":
329 if not data.getVar('TINDER_AUTOBUILD', event.data, True) == "0":
330 build.exec_task('do_clean', event.data)
331 log += "<--- TINDERBOX Package %s failed (FAILURE)\n" % data.getVar('PF', event.data, True)
333 # remember the failure for the -k case
334 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
336 elif name == "BuildCompleted":
337 log += "Build Completed\n"
339 # Check if we have a old status...
341 h = file(data.getVar('TMPDIR',event.data,True)+'/tinder-status', 'r')
342 status = int(h.read())
346 elif name == "MultipleProviders":
347 log += "---> TINDERBOX Multiple Providers\n"
348 log += "multiple providers are available (%s);\n" % ", ".join(event.getCandidates())
349 log += "consider defining PREFERRED_PROVIDER_%s\n" % event.getItem()
350 log += "is runtime: %d\n" % event.isRuntime()
351 log += "<--- TINDERBOX Multiple Providers\n"
352 elif name == "NoProvider":
353 log += "Error: No Provider for: %s\n" % event.getItem()
354 log += "Error:Was Runtime: %d\n" % event.isRuntime()
356 # remember the failure for the -k case
357 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
364 # for now we will use the http post method as it is the only one
365 log_post_method = tinder_send_http
366 log_post_method(event.data, status, log)
369 # we want to be an event handler
370 addhandler tinderclient_eventhandler
371 python tinderclient_eventhandler() {
372 from bb import note, error, data
373 from bb.event import NotHandled
378 do_tinder_report = data.getVar('TINDER_REPORT', e.data, True)
379 if do_tinder_report and do_tinder_report == "1":
380 tinder_do_tinder_report(e)