nm-applet: fix some buildproblems
[openembedded.git] / classes / tinderclient.bbclass
blobd2b2b3389840b65ca7b256685ce36503184d03d4
1 def tinder_http_post(d, server, selector, content_type, body):
2     import httplib
3     from bb import data
4     # now post it
5     for i in range(0,5):
6        try:
7            proxy = data.getVar('HTTP_PROXY', d, True )
8            if (proxy):
9                    if (proxy.endswith('/')):
10                            proxy = proxy[:-1]
11                    if (proxy.startswith('http://')):
12                            proxy = proxy[7:]
13                    h = httplib.HTTP(proxy)
14                    h.putrequest('POST', 'http://%s%s' % (server, selector))
15            else:
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)))
20            h.endheaders()
21            h.send(body)
22            errcode, errmsg, headers = h.getreply()
23            #print errcode, errmsg, headers
24            return (errcode,errmsg, headers, h.file)
25        except Exception, e:
26            print "Error sending the report! ", e
27            # try again
28            pass
30     # return some garbage
31     return (-1, "unknown", "unknown", None)
33 def tinder_form_data(bound, dict, log):
34     output = []
35     # for each key in the dictionary
36     for name in dict:
37         assert dict[name]
38         output.append( "--" + bound )
39         output.append( 'Content-Disposition: form-data; name="%s"' % name )
40         output.append( "" )
41         output.append( dict[name] )
42     if log:
43         output.append( "--" + bound )
44         output.append( 'Content-Disposition: form-data; name="log"; filename="log.txt"' )
45         output.append( '' )
46         output.append( log )
47     output.append( '--' + bound + '--' )
48     output.append( '' )
50     return "\r\n".join(output)
52 def tinder_time_string():
53     """
54     Return the time as GMT
55     """
56     return ""
58 def tinder_format_http_post(d,status,log):
59     """
60     Format the Tinderbox HTTP post with the data needed
61     for the tinderbox to be happy.
62     """
64     from bb import data, build
65     import os,random
67     # the variables we will need to send on this form post
68     variables =  {
69         "tree"         : data.getVar('TINDER_TREE',    d, True),
70         "machine_name" : data.getVar('TINDER_MACHINE', d, True),
71         "os"           : os.uname()[0],
72         "os_version"   : os.uname()[2],
73         "compiler"     : "gcc",
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",
86     }
88     # optionally add the status
89     if 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
95     try:
96         f = file(data.getVar('TMPDIR',d,True)+'/tinder-machine.id', 'r')
97         id = f.read()
98         variables['machine_id'] = id
99     except:
100         pass
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):
112     """
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
115     on the server.
116     """
117     from bb import data
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)
128     # now post it
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("'")]
138     import bb
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')
144     f.write(report)
147 def tinder_send_http(d, status, _log):
148     """
149     Send this log as build status
150     """
151     from bb import data
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
161     new_log = _log
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
166         #print h.file.read()
167         new_log = new_log[18000:]
170 def tinder_print_info(d):
171     """
172     Print the TinderBox Info
173         Including informations of the BaseSystem and the Tree
174         we use.
175     """
177     from   bb import data
178     import os
179     # get the local vars
181     time    = tinder_time_string()
182     ops     = os.uname()[0]
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
197     # bug as well
198     output = []
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():
225     """
226     Print the environment variables of this build
227     """
228     from bb import data
229     import os
231     time_start = tinder_time_string()
232     time_end   = tinder_time_string()
234     # build the environment
235     env = ""
236     for var in os.environ:
237         env += "%s=%s\n" % (var, os.environ[var])
239     output = []
240     output.append( "---> TINDERBOX RUNNING env %(time_start)s" )
241     output.append( env )
242     output.append( "<--- TINDERBOX FINISHED (SUCCESS) %(time_end)s" )
244     return "\n".join(output) % vars()
246 def tinder_tinder_start(d, event):
247     """
248     PRINT the configuration of this build
249     """
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() ) 
257     output = []
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" )
265     output.append( "" )
267     return "\n".join(output) % vars()
269 def tinder_do_tinder_report(event):
270     """
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
279     implemented yet.
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.
288     """
289     from bb.event import getName
290     from bb import data, mkdirhier, build
291     import os, glob
293     # variables
294     name = getName(event)
295     log  = ""
296     status = 1
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)
302         try:
303             # truncate the tinder log file
304             f = file(data.getVar('TINDER_LOG', event.data, True), 'w')
305             f.write("")
306             f.close()
307         except:
308             pass
310         try:
311             # write a status to the file. This is needed for the -k option
312             # of BitBake
313             g = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
314             g.write("")
315             g.close()
316         except IOError:
317             pass
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)
343         status = 200
344         # remember the failure for the -k case
345         h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
346         h.write("200")
347     elif name == "BuildCompleted":
348         log += "Build Completed\n"
349         status = 100
350         # Check if we have a old status...
351         try:
352             h = file(data.getVar('TMPDIR',event.data,True)+'/tinder-status', 'r')
353             status = int(h.read())
354         except:
355             pass
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()
366         status = 200
367         # remember the failure for the -k case
368         h = file(data.getVar('TMPDIR', event.data, True)+"/tinder-status", 'w')
369         h.write("200")
371     # now post the log
372     if len(log) == 0:
373         return
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":
387         return NotHandled
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)
393     return NotHandled