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
28 output.append( "--" + bound )
29 output.append( 'Content-Disposition: form-data; name="%s"' % name )
31 output.append( dict[name] )
33 output.append( "--" + bound )
34 output.append( 'Content-Disposition: form-data; name="log"; filename="log.txt"' )
37 output.append( '--' + bound + '--' )
40 return "\r\n".join(output)
42 def tinder_time_string():
44 Return the time as GMT
48 def tinder_format_http_post(d,status,log):
50 Format the Tinderbox HTTP post with the data needed
51 for the tinderbox to be happy.
54 from bb import data, build
57 # the variables we will need to send on this form post
59 "tree" : data.getVar('TINDER_TREE', d, True),
60 "machine_name" : data.getVar('TINDER_MACHINE', d, True),
62 "os_version" : os.uname()[2],
64 "clobber" : data.getVar('TINDER_CLOBBER', d, True) or "0",
65 "srcdate" : data.getVar('SRCDATE', d, True),
66 "PN" : data.getVar('PN', d, True),
67 "PV" : data.getVar('PV', d, True),
68 "PR" : data.getVar('PR', d, True),
69 "FILE" : data.getVar('FILE', d, True) or "N/A",
70 "TARGETARCH" : data.getVar('TARGET_ARCH', d, True),
71 "TARGETFPU" : data.getVar('TARGET_FPU', d, True) or "Unknown",
72 "TARGETOS" : data.getVar('TARGET_OS', d, True) or "Unknown",
73 "MACHINE" : data.getVar('MACHINE', d, True) or "Unknown",
74 "DISTRO" : data.getVar('DISTRO', d, True) or "Unknown",
75 "zecke-rocks" : "sure",
78 # optionally add the status
80 variables["status"] = str(status)
82 # try to load the machine id
83 # we only need on build_status.pl but sending it
84 # always does not hurt
86 f = file(data.getVar('TMPDIR',d,True)+'/tinder-machine.id', 'r')
88 variables['machine_id'] = id
92 # the boundary we will need
93 boundary = "----------------------------------%d" % int(random.random()*1000000000000)
96 body = tinder_form_data( boundary, variables, log )
98 return ("multipart/form-data; boundary=%s" % boundary),body
101 def tinder_build_start(d):
103 Inform the tinderbox that a build is starting. We do this
104 by posting our name and tree to the build_start.pl script
109 # get the body and type
110 content_type, body = tinder_format_http_post(d,None,None)
111 server = data.getVar('TINDER_HOST', d, True )
112 url = data.getVar('TINDER_URL', d, True )
114 selector = url + "/xml/build_start.pl"
116 #print "selector %s and url %s" % (selector, url)
119 errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
120 #print errcode, errmsg, headers
121 report = h_file.read()
123 # now let us find the machine id that was assigned to us
124 search = "<machine id='"
125 report = report[report.find(search)+len(search):]
126 report = report[0:report.find("'")]
129 bb.note("Machine ID assigned by tinderbox: %s" % report )
131 # now we will need to save the machine number
132 # we will override any previous numbers
133 f = file(data.getVar('TMPDIR', d, True)+"/tinder-machine.id", 'w')
137 def tinder_send_http(d, status, _log):
139 Send this log as build status
144 # get the body and type
145 server = data.getVar('TINDER_HOST', d, True )
146 url = data.getVar('TINDER_URL', d, True )
148 selector = url + "/xml/build_status.pl"
150 # now post it - in chunks of 10.000 charachters
152 while len(new_log) > 0:
153 content_type, body = tinder_format_http_post(d,status,new_log[0:18000])
154 errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
155 #print errcode, errmsg, headers
157 new_log = new_log[18000:]
160 def tinder_print_info(d):
162 Print the TinderBox Info
163 Including informations of the BaseSystem and the Tree
171 time = tinder_time_string()
173 version = os.uname()[2]
174 url = data.getVar( 'TINDER_URL' , d, True )
175 tree = data.getVar( 'TINDER_TREE', d, True )
176 branch = data.getVar( 'TINDER_BRANCH', d, True )
177 srcdate = data.getVar( 'SRCDATE', d, True )
178 machine = data.getVar( 'MACHINE', d, True )
179 distro = data.getVar( 'DISTRO', d, True )
180 bbfiles = data.getVar( 'BBFILES', d, True )
181 tarch = data.getVar( 'TARGET_ARCH', d, True )
182 fpu = data.getVar( 'TARGET_FPU', d, True )
183 oerev = data.getVar( 'OE_REVISION', d, True ) or "unknown"
185 # there is a bug with tipple quoted strings
186 # i will work around but will fix the original
189 output.append("== Tinderbox Info" )
190 output.append("Time: %(time)s" )
191 output.append("OS: %(ops)s" )
192 output.append("%(version)s" )
193 output.append("Compiler: gcc" )
194 output.append("Tinderbox Client: 0.1" )
195 output.append("Tinderbox Client Last Modified: yesterday" )
196 output.append("Tinderbox Protocol: 0.1" )
197 output.append("URL: %(url)s" )
198 output.append("Tree: %(tree)s" )
199 output.append("Config:" )
200 output.append("branch = '%(branch)s'" )
201 output.append("TARGET_ARCH = '%(tarch)s'" )
202 output.append("TARGET_FPU = '%(fpu)s'" )
203 output.append("SRCDATE = '%(srcdate)s'" )
204 output.append("MACHINE = '%(machine)s'" )
205 output.append("DISTRO = '%(distro)s'" )
206 output.append("BBFILES = '%(bbfiles)s'" )
207 output.append("OEREV = '%(oerev)s'" )
208 output.append("== End Tinderbox Client Info" )
210 # now create the real output
211 return "\n".join(output) % vars()
214 def tinder_print_env():
216 Print the environment variables of this build
221 time_start = tinder_time_string()
222 time_end = tinder_time_string()
224 # build the environment
226 for var in os.environ:
227 env += "%s=%s\n" % (var, os.environ[var])
230 output.append( "---> TINDERBOX RUNNING env %(time_start)s" )
232 output.append( "<--- TINDERBOX FINISHED (SUCCESS) %(time_end)s" )
234 return "\n".join(output) % vars()
236 def tinder_tinder_start(d, event):
238 PRINT the configuration of this build
241 time_start = tinder_time_string()
242 config = tinder_print_info(d)
243 #env = tinder_print_env()
244 time_end = tinder_time_string()
245 packages = " ".join( event.getPkgs() )
248 output.append( "---> TINDERBOX PRINTING CONFIGURATION %(time_start)s" )
249 output.append( config )
250 #output.append( env )
251 output.append( "<--- TINDERBOX FINISHED PRINTING CONFIGURATION %(time_end)s" )
252 output.append( "---> TINDERBOX BUILDING '%(packages)s'" )
253 output.append( "<--- TINDERBOX STARTING BUILD NOW" )
257 return "\n".join(output) % vars()
259 def tinder_do_tinder_report(event):
261 Report to the tinderbox:
262 On the BuildStart we will inform the box directly
263 On the other events we will write to the TINDER_LOG and
264 when the Task is finished we will send the report.
266 The above is not yet fully implemented. Currently we send
267 information immediately. The caching/queuing needs to be
268 implemented. Also sending more or less information is not
271 We have two temporary files stored in the TMP directory. One file
272 contains the assigned machine id for the tinderclient. This id gets
273 assigned when we connect the box and start the build process the second
274 file is used to workaround an EventHandler limitation. If BitBake is ran
275 with the continue option we want the Build to fail even if we get the
276 BuildCompleted Event. In this case we have to look up the status and
277 send it instead of 100/success.
279 from bb.event import getName
280 from bb import data, mkdirhier, build
284 name = getName(event)
287 # Check what we need to do Build* shows we start or are done
288 if name == "BuildStarted":
289 tinder_build_start(event.data)
290 log = tinder_tinder_start(event.data,event)
293 # truncate the tinder log file
294 f = file(data.getVar('TINDER_LOG', event.data, True), 'w')
301 # write a status to the file. This is needed for the -k option
303 g = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
309 # Append the Task-Log (compile,configure...) to the log file
310 # we will send to the server
311 if name == "TaskSucceeded" or name == "TaskFailed":
312 log_file = glob.glob("%s/log.%s.*" % (data.getVar('T', event.data, True), event.task))
314 if len(log_file) != 0:
315 to_file = data.getVar('TINDER_LOG', event.data, True)
316 log += "".join(open(log_file[0], 'r').readlines())
318 # set the right 'HEADER'/Summary for the TinderBox
319 if name == "TaskStarted":
320 log += "---> TINDERBOX Task %s started\n" % event.task
321 elif name == "TaskSucceeded":
322 log += "<--- TINDERBOX Task %s done (SUCCESS)\n" % event.task
323 elif name == "TaskFailed":
324 log += "<--- TINDERBOX Task %s failed (FAILURE)\n" % event.task
325 elif name == "PkgStarted":
326 log += "---> TINDERBOX Package %s started\n" % data.getVar('PF', event.data, True)
327 elif name == "PkgSucceeded":
328 log += "<--- TINDERBOX Package %s done (SUCCESS)\n" % data.getVar('PF', event.data, True)
329 elif name == "PkgFailed":
330 if not data.getVar('TINDER_AUTOBUILD', event.data, True) == "0":
331 build.exec_func('do_clean', event.data)
332 log += "<--- TINDERBOX Package %s failed (FAILURE)\n" % data.getVar('PF', event.data, True)
334 # remember the failure for the -k case
335 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
337 elif name == "BuildCompleted":
338 log += "Build Completed\n"
340 # Check if we have a old status...
342 h = file(data.getVar('TMPDIR',event.data,True)+'/tinder-status', 'r')
343 status = int(h.read())
347 elif name == "MultipleProviders":
348 log += "---> TINDERBOX Multiple Providers\n"
349 log += "multiple providers are available (%s);\n" % ", ".join(event.getCandidates())
350 log += "consider defining PREFERRED_PROVIDER_%s\n" % event.getItem()
351 log += "is runtime: %d\n" % event.isRuntime()
352 log += "<--- TINDERBOX Multiple Providers\n"
353 elif name == "NoProvider":
354 log += "Error: No Provider for: %s\n" % event.getItem()
355 log += "Error:Was Runtime: %d\n" % event.isRuntime()
357 # remember the failure for the -k case
358 h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
365 # for now we will use the http post method as it is the only one
366 log_post_method = tinder_send_http
367 log_post_method(event.data, status, log)
370 # we want to be an event handler
371 addhandler tinderclient_eventhandler
372 python tinderclient_eventhandler() {
373 from bb import note, error, data
374 from bb.event import NotHandled, getName
376 if e.data is None or getName(e) == "MsgNote":
379 do_tinder_report = data.getVar('TINDER_REPORT', e.data, True)
380 if do_tinder_report and do_tinder_report == "1":
381 tinder_do_tinder_report(e)