merge of 3bc4777e54539885e842fcbb48be4faf5b6f0183
[vuplus_openembedded] / classes / tinderclient.bbclass
1 def tinder_http_post(server, selector, content_type, body):
2     import httplib
3     # now post it
4     for i in range(0,5):
5        try:
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)))
10            h.endheaders()
11            h.send(body)
12            errcode, errmsg, headers = h.getreply()
13            #print errcode, errmsg, headers
14            return (errcode,errmsg, headers, h.file)
15        except:
16            # try again
17            pass
18
19 def tinder_form_data(bound, dict, log):
20     output = []
21   #br
22     # for each key in the dictionary
23     for name in dict:
24         output.append( "--" + bound )
25         output.append( 'Content-Disposition: form-data; name="%s"' % name )
26         output.append( "" )
27         output.append( dict[name] )
28     if log:
29         output.append( "--" + bound )
30         output.append( 'Content-Disposition: form-data; name="log"; filename="log.txt"' )
31         output.append( '' )
32         output.append( log )
33     output.append( '--' + bound + '--' )
34     output.append( '' )
35
36     return "\r\n".join(output)
37
38 def tinder_time_string():
39     """
40     Return the time as GMT
41     """
42     return ""
43
44 def tinder_format_http_post(d,status,log):
45     """
46     Format the Tinderbox HTTP post with the data needed
47     for the tinderbox to be happy.
48     """
49
50     from bb import data, build
51     import os,random
52
53     # the variables we will need to send on this form post
54     variables =  {
55         "tree"         : data.getVar('TINDER_TREE',    d, True),
56         "machine_name" : data.getVar('TINDER_MACHINE', d, True),
57         "os"           : os.uname()[0],
58         "os_version"   : os.uname()[2],
59         "compiler"     : "gcc",
60         "clobber"      : data.getVar('TINDER_CLOBBER', d, True)
61     }
62
63     # optionally add the status
64     if status:
65         variables["status"] = str(status)
66
67     # try to load the machine id
68     # we only need on build_status.pl but sending it
69     # always does not hurt
70     try:
71         f = file(data.getVar('TMPDIR',d,True)+'/tinder-machine.id', 'r')
72         id = f.read()
73         variables['machine_id'] = id
74     except:
75         pass
76
77     # the boundary we will need
78     boundary = "----------------------------------%d" % int(random.random()*1000000000000)
79
80     # now format the body
81     body = tinder_form_data( boundary, variables, log )
82
83     return ("multipart/form-data; boundary=%s" % boundary),body
84
85
86 def tinder_build_start(d):
87     """
88     Inform the tinderbox that a build is starting. We do this
89     by posting our name and tree to the build_start.pl script
90     on the server.
91     """
92     from bb import data
93
94     # get the body and type
95     content_type, body = tinder_format_http_post(d,None,None)
96     server = data.getVar('TINDER_HOST', d, True )
97     url    = data.getVar('TINDER_URL',  d, True )
98
99     selector = url + "/xml/build_start.pl"
100
101     #print "selector %s and url %s" % (selector, url)
102
103     # now post it
104     errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
105     #print errcode, errmsg, headers
106     report = h_file.read()
107
108     # now let us find the machine id that was assigned to us
109     search = "<machine id='"
110     report = report[report.find(search)+len(search):]
111     report = report[0:report.find("'")]
112
113     import bb
114     bb.note("Machine ID assigned by tinderbox: %s" % report )
115
116     # now we will need to save the machine number
117     # we will override any previous numbers
118     f = file(data.getVar('TMPDIR', d, True)+"/tinder-machine.id", 'w')
119     f.write(report)
120
121
122 def tinder_send_http(d, status, log):
123     """
124     Send this log as build status
125     """
126     from bb import data
127
128
129     # get the body and type
130     content_type, body = tinder_format_http_post(d,status,log)
131     server = data.getVar('TINDER_HOST', d, True )
132     url    = data.getVar('TINDER_URL',  d, True )
133
134     selector = url + "/xml/build_status.pl"
135
136     # now post it
137     errcode, errmsg, headers, h_file = tinder_http_post(server,selector,content_type, body)
138     #print errcode, errmsg, headers
139     #print h.file.read()
140
141
142 def tinder_print_info(d):
143     """
144     Print the TinderBox Info
145         Including informations of the BaseSystem and the Tree
146         we use.
147     """
148
149     from   bb import data
150     import os
151     # get the local vars
152
153     time    = tinder_time_string()
154     ops     = os.uname()[0]
155     version = os.uname()[2]
156     url     = data.getVar( 'TINDER_URL' , d, True )
157     tree    = data.getVar( 'TINDER_TREE', d, True )
158     branch  = data.getVar( 'TINDER_BRANCH', d, True )
159     srcdate = data.getVar( 'SRCDATE', d, True )
160     machine = data.getVar( 'MACHINE', d, True )
161     distro  = data.getVar( 'DISTRO',  d, True )
162     bbfiles = data.getVar( 'BBFILES', d, True )
163     tarch   = data.getVar( 'TARGET_ARCH', d, True )
164     fpu     = data.getVar( 'TARGET_FPU', d, True )
165     oerev   = data.getVar( 'OE_REVISION', d, True ) or "unknown"
166
167     # there is a bug with tipple quoted strings
168     # i will work around but will fix the original
169     # bug as well
170     output = []
171     output.append("== Tinderbox Info" )
172     output.append("Time: %(time)s" )
173     output.append("OS: %(ops)s" )
174     output.append("%(version)s" )
175     output.append("Compiler: gcc" )
176     output.append("Tinderbox Client: 0.1" )
177     output.append("Tinderbox Client Last Modified: yesterday" )
178     output.append("Tinderbox Protocol: 0.1" )
179     output.append("URL: %(url)s" )
180     output.append("Tree: %(tree)s" )
181     output.append("Config:" )
182     output.append("branch = '%(branch)s'" )
183     output.append("TARGET_ARCH = '%(tarch)s'" )
184     output.append("TARGET_FPU = '%(fpu)s'" )
185     output.append("SRCDATE = '%(srcdate)s'" )
186     output.append("MACHINE = '%(machine)s'" )
187     output.append("DISTRO = '%(distro)s'" )
188     output.append("BBFILES = '%(bbfiles)s'" )
189     output.append("OEREV = '%(oerev)s'" )
190     output.append("== End Tinderbox Client Info" )
191
192     # now create the real output
193     return "\n".join(output) % vars()
194
195
196 def tinder_print_env():
197     """
198     Print the environment variables of this build
199     """
200     from bb import data
201     import os
202
203     time_start = tinder_time_string()
204     time_end   = tinder_time_string()
205
206     # build the environment
207     env = ""
208     for var in os.environ:
209         env += "%s=%s\n" % (var, os.environ[var])
210
211     output = []
212     output.append( "---> TINDERBOX RUNNING env %(time_start)s" )
213     output.append( env )
214     output.append( "<--- TINDERBOX FINISHED (SUCCESS) %(time_end)s" )
215
216     return "\n".join(output) % vars()
217
218 def tinder_tinder_start(d, event):
219     """
220     PRINT the configuration of this build
221     """
222
223     time_start = tinder_time_string()
224     config = tinder_print_info(d)
225     #env    = tinder_print_env()
226     time_end   = tinder_time_string()
227     packages = " ".join( event.getPkgs() ) 
228
229     output = []
230     output.append( "---> TINDERBOX PRINTING CONFIGURATION %(time_start)s" )
231     output.append( config )
232     #output.append( env    )
233     output.append( "<--- TINDERBOX FINISHED PRINTING CONFIGURATION %(time_end)s" )
234     output.append( "---> TINDERBOX BUILDING '%(packages)s'" )
235     output.append( "<--- TINDERBOX STARTING BUILD NOW" )
236
237     output.append( "" ) 
238  
239     return "\n".join(output) % vars()
240
241 def tinder_do_tinder_report(event):
242     """
243     Report to the tinderbox:
244         On the BuildStart we will inform the box directly
245         On the other events we will write to the TINDER_LOG and
246         when the Task is finished we will send the report.
247
248     The above is not yet fully implemented. Currently we send
249     information immediately. The caching/queuing needs to be
250     implemented. Also sending more or less information is not
251     implemented yet.
252     """
253     from bb.event import getName
254     from bb import data, mkdirhier, build
255     import os, glob
256
257     # variables
258     name = getName(event)
259     log  = ""
260     status = 1
261     #print asd 
262     # Check what we need to do Build* shows we start or are done
263     if name == "BuildStarted":
264         tinder_build_start(event.data)
265         log = tinder_tinder_start(event.data,event)
266
267         try:
268             # truncate the tinder log file
269             f = file(data.getVar('TINDER_LOG', event.data, True), 'rw+')
270             f.truncate(0)
271             f.close()
272         except IOError:
273             pass
274
275     # Append the Task-Log (compile,configure...) to the log file
276     # we will send to the server
277     if name == "TaskSucceeded" or name == "TaskFailed":
278         log_file = glob.glob("%s/log.%s.*" % (data.getVar('T', event.data, True), event.task))
279
280         if len(log_file) != 0:
281             to_file  = data.getVar('TINDER_LOG', event.data, True)
282             log     += "".join(open(log_file[0], 'r').readlines())
283
284     # set the right 'HEADER'/Summary for the TinderBox
285     if name == "TaskStarted":
286         log += "---> TINDERBOX Task %s started\n" % event.task
287     elif name == "TaskSucceeded":
288         log += "<--- TINDERBOX Task %s done (SUCCESS)\n" % event.task
289     elif name == "TaskFailed":
290         log += "<--- TINDERBOX Task %s failed (FAILURE)\n" % event.task
291     elif name == "PkgStarted":
292         log += "---> TINDERBOX Package %s started\n" % data.getVar('P', event.data, True)
293     elif name == "PkgSucceeded":
294         log += "<--- TINDERBOX Package %s done (SUCCESS)\n" % data.getVar('P', event.data, True)
295     elif name == "PkgFailed":
296         build.exec_task('do_clean', event.data)
297         log += "<--- TINDERBOX Package %s failed (FAILURE)\n" % data.getVar('P', event.data, True)
298         status = 200
299     elif name == "BuildCompleted":
300         log += "Build Completed\n"
301         status = 100
302     elif name == "MultipleProviders":
303         log += "---> TINDERBOX Multiple Providers\n"
304         log += "multiple providers are available (%s);\n" % ", ".join(event.getCandidates())
305         log += "consider defining PREFERRED_PROVIDER_%s\n" % event.getItem()
306         log += "is runtime: %d\n" % event.isRuntime()
307         log += "<--- TINDERBOX Multiple Providers\n"
308     elif name == "NoProvider":
309         log += "Error: No Provider for: %s\n" % event.getItem()
310         log += "Error:Was Runtime: %d\n" % event.isRuntime()
311         status = 200
312
313     # now post the log
314     if len(log) == 0:
315         return
316
317     # for now we will use the http post method as it is the only one
318     log_post_method = tinder_send_http
319     log_post_method(event.data, status, log)
320
321
322 # we want to be an event handler
323 addhandler tinderclient_eventhandler
324 python tinderclient_eventhandler() {
325     from bb import note, error, data
326     from bb.event import NotHandled
327     do_tinder_report = data.getVar('TINDER_REPORT', e.data, True)
328     if do_tinder_report and do_tinder_report == "1":
329         tinder_do_tinder_report(e)
330
331     return NotHandled
332 }