blob: dfd419418430b728da24b91c04665082f2e04680 [file] [log] [blame]
mbligh2e4e5df2007-11-05 17:22:46 +00001#!/usr/bin/python
2
3"""
4Selects all rows and columns that satisfy the condition specified
5and draws the matrix. There is a seperate SQL query made for every (x,y)
6in the matrix.
7"""
8
mbligh2e4e5df2007-11-05 17:22:46 +00009print "Content-type: text/html\n"
mbligh44710b62008-03-07 00:25:43 +000010import cgi, cgitb, re, datetime, query_lib
mbligha4266932007-11-05 18:12:16 +000011import sys, os
mblighb180f6c2008-01-04 20:24:41 +000012import urllib
mbligh2e4e5df2007-11-05 17:22:46 +000013
14tko = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0])))
15sys.path.insert(0, tko)
16
mbligh2b672532007-11-05 19:24:51 +000017import display, frontend, db, query_lib
mbligh12eebfa2008-01-03 02:01:53 +000018client_bin = os.path.abspath(os.path.join(tko, '../client/bin'))
19sys.path.insert(0, client_bin)
20import kernel_versions
21
mbligh190a81d2007-11-05 20:40:38 +000022html_header = """\
23<form action="compose_query.cgi" method="get">
24<table border="0">
25<tr>
26 <td>Column: </td>
27 <td>Row: </td>
28 <td>Condition: </td>
mbligh44710b62008-03-07 00:25:43 +000029 <td align="center">
30 <a href="http://test.kernel.org/autotest/AutotestTKOCondition">Help</a>
31 </td>
mbligh190a81d2007-11-05 20:40:38 +000032</tr>
33<tr>
34 <td>
35 <SELECT NAME="columns">
36 %s
37 </SELECT>
38 </td>
39 <td>
40 <SELECT NAME="rows">
41 %s
42 </SELECT>
43 </td>
44 <td>
mbligh44710b62008-03-07 00:25:43 +000045 <input type="text" name="condition" size="30" value="%s">
mblighbe257452008-04-16 23:29:13 +000046 <input type="hidden" name="title" value="%s">
mbligh190a81d2007-11-05 20:40:38 +000047 </td>
48 <td align="center"><input type="submit" value="Submit">
49 </td>
50</tr>
51</table>
52</form>
53"""
54
mbligh12eebfa2008-01-03 02:01:53 +000055
mbligh5dd503b2008-01-03 16:35:27 +000056next_field = {
mbligh44710b62008-03-07 00:25:43 +000057 'machine_group': 'hostname',
58 'hostname': 'tag',
59 'tag': 'tag',
mbligh5dd503b2008-01-03 16:35:27 +000060
mbligh44710b62008-03-07 00:25:43 +000061 'kernel': 'test',
62 'test': 'label',
63 'label': 'tag',
mbligh5dd503b2008-01-03 16:35:27 +000064
mbligh44710b62008-03-07 00:25:43 +000065 'reason': 'tag',
66 'user': 'tag',
67 'status': 'tag',
68
mbligh5bb55862008-04-16 23:09:31 +000069 'time': 'tag',
70 'time_daily': 'time',
mbligh5dd503b2008-01-03 16:35:27 +000071}
72
73
mbligh11204f82008-04-16 23:30:07 +000074def parse_field(form, form_field, field_default):
75 if not form_field in form:
76 return field_default
mbligh12eebfa2008-01-03 02:01:53 +000077 field_input = form[form_field].value.lower()
mbligh2ba3e732008-01-16 01:30:19 +000078 if field_input and field_input in frontend.test_view_field_dict:
mbligh12eebfa2008-01-03 02:01:53 +000079 return field_input
mbligh11204f82008-04-16 23:30:07 +000080 return field_default
mbligh12eebfa2008-01-03 02:01:53 +000081
82
83def parse_condition(form, form_field, field_default):
84 if not form_field in form:
85 return field_default
86 return form[form_field].value
87
88
89form = cgi.FieldStorage()
mbligh3d7a5f52008-04-16 23:06:36 +000090
mblighbe257452008-04-16 23:29:13 +000091title_field = parse_condition(form, 'title', '')
mbligh3d7a5f52008-04-16 23:06:36 +000092try:
93 row = parse_field(form, 'rows')
94 column = parse_field(form, 'columns')
95 condition_field = parse_condition(form, 'condition','')
mblighbe257452008-04-16 23:29:13 +000096
mbligh3d7a5f52008-04-16 23:06:36 +000097except KeyError:
98 ## first time here
99 ## to start faster, begin with records of last week only
100 cut_off = datetime.datetime.now() - datetime.timedelta(7)
101 cut_off = datetime.date(cut_off.year, cut_off.month, cut_off.day)
102 condition_field = parse_condition(form, 'condition',
103 "time > '%s'" % str(cut_off))
104 row = 'kernel'
105 column = 'machine_group'
106
mbligh44710b62008-03-07 00:25:43 +0000107
mbligh439661b2008-02-19 15:57:53 +0000108## caller can specify rows and columns that shall be included into the report
109## regardless of whether actual test data is available yet
110force_row_field = parse_condition(form,'force_row','')
111force_column_field = parse_condition(form,'force_column','')
mbligh190a81d2007-11-05 20:40:38 +0000112
mbligh439661b2008-02-19 15:57:53 +0000113def split_forced_fields(force_field):
114 if force_field:
115 return force_field.split()
116 else:
117 return []
118
119force_row = split_forced_fields(force_row_field)
120force_column = split_forced_fields(force_column_field)
121
mbligh2e4e5df2007-11-05 17:22:46 +0000122cgitb.enable()
mblighaea09602008-04-16 22:59:37 +0000123db_obj = db.db()
mbligh2e4e5df2007-11-05 17:22:46 +0000124
mbligh12eebfa2008-01-03 02:01:53 +0000125
mbligh2ba3e732008-01-16 01:30:19 +0000126def construct_link(x, y):
127 next_row = row
128 next_column = column
mbligh5dd503b2008-01-03 16:35:27 +0000129 condition_list = []
130 if condition_field != '':
131 condition_list.append(condition_field)
mbligh2ba3e732008-01-16 01:30:19 +0000132 if y:
133 next_row = next_field[row]
134 condition_list.append("%s='%s'" % (row, y))
135 if x:
136 next_column = next_field[column]
137 condition_list.append("%s='%s'" % (column, x))
mblighb180f6c2008-01-04 20:24:41 +0000138 next_condition = '&'.join(condition_list)
mblighbe257452008-04-16 23:29:13 +0000139 link = 'compose_query.cgi?' + urllib.urlencode({'columns': next_column,
140 'rows': next_row, 'condition': next_condition,
141 'title': title_field})
142 return link
mbligh5dd503b2008-01-03 16:35:27 +0000143
144
mbligh12eebfa2008-01-03 02:01:53 +0000145def create_select_options(selected_val):
mbligh190a81d2007-11-05 20:40:38 +0000146 ret = ""
mbligh2ba3e732008-01-16 01:30:19 +0000147 for option in sorted(frontend.test_view_field_dict.keys()):
mbligh190a81d2007-11-05 20:40:38 +0000148 if selected_val == option:
149 selected = " SELECTED"
150 else:
151 selected = ""
152
mbligh2ba3e732008-01-16 01:30:19 +0000153 ret += '<OPTION VALUE="%s"%s>%s</OPTION>\n' % \
154 (option, selected, option)
mbligh190a81d2007-11-05 20:40:38 +0000155 return ret
156
157
apw7a7316b2008-02-21 17:42:05 +0000158def map_kernel_base(kernel_name):
mbligh439661b2008-02-19 15:57:53 +0000159 ## insert <br> after each / in kernel name
160 ## but spare consequtive //
mbligh8e7c78e2008-02-20 21:18:49 +0000161 kernel_name = kernel_name.replace('/','/<br>')
162 kernel_name = kernel_name.replace('/<br>/<br>','//')
mbligh439661b2008-02-19 15:57:53 +0000163 return kernel_name
164
165
mbligh44710b62008-03-07 00:25:43 +0000166def header_tuneup(field_name, header):
167 ## header tune up depends on particular field name and may include:
168 ## - breaking header into several strings if it is long url
169 ## - creating date from datetime stamp
170 ## - possibly, expect more various refinements for different fields
171 if field_name == 'kernel':
172 return map_kernel_base(header)
mbligh44710b62008-03-07 00:25:43 +0000173 else:
174 return header
175
176
apw7a7316b2008-02-21 17:42:05 +0000177# Kernel name mappings -- the kernels table 'printable' field is
178# effectively a sortable identifier for the kernel It encodes the base
179# release which is used for overall sorting, plus where patches are
180# applied it adds an increasing pNNN patch combination identifier
181# (actually the kernel_idx for the entry). This allows sorting
182# as normal by the base kernel version and then sub-sorting by the
183# "first time we saw" a patch combination which should keep them in
184# approximatly date order. This patch identifier is not suitable
185# for display, so we have to map it to a suitable html fragment for
186# display. This contains the kernel base version plus the truncated
187# names of all the patches,
188#
189# 2.6.24-mm1 p112
190# +add-new-string-functions-
191# +x86-amd-thermal-interrupt
192#
193# This mapping is produced when the first mapping is request, with
194# a single query over the patches table; the result is then cached.
195#
196# Note: that we only count a base version as patched if it contains
197# patches which are not already "expressed" in the base version.
198# This includes both -gitN and -mmN kernels.
199map_kernel_map = None
200
201
202def map_kernel_init():
203 fields = ['base', 'k.kernel_idx', 'name', 'url']
204 map = {}
mblighaea09602008-04-16 22:59:37 +0000205 for (base, idx, name, url) in db_obj.select(','.join(fields),
apw7a7316b2008-02-21 17:42:05 +0000206 'kernels k,patches p', 'k.kernel_idx=p.kernel_idx'):
207 match = re.match(r'.*(-mm[0-9]+|-git[0-9]+)\.(bz2|gz)$', url)
208 if match:
209 continue
210
211 key = base + ' p%d' % (idx)
212 if not map.has_key(key):
213 map[key] = map_kernel_base(base) + ' p%d' % (idx)
214 map[key] += '<br>+<span title="' + name + '">' + name[0:25] + '</span>'
215
216 return map
217
218
219def map_kernel(name):
220 global map_kernel_map
221 if map_kernel_map == None:
222 map_kernel_map = map_kernel_init()
223
224 if map_kernel_map.has_key(name):
225 return map_kernel_map[name]
226
227 return map_kernel_base(name.split(' ')[0])
228
229
230field_map = {
231 'kernel':map_kernel
232}
233
234
mbligh12eebfa2008-01-03 02:01:53 +0000235def gen_matrix():
mbligh12eebfa2008-01-03 02:01:53 +0000236 where = None
237 if condition_field.strip() != '':
mbligh44710b62008-03-07 00:25:43 +0000238 try:
239 where = query_lib.parse_scrub_and_gen_condition(
240 condition_field, frontend.test_view_field_dict)
241 print "<!-- where clause: %s -->" % (where,)
242 except:
243 msg = "Unspecified error when parsing condition"
244 return [[display.box(msg)]]
mbligh2e4e5df2007-11-05 17:22:46 +0000245
mblighaea09602008-04-16 22:59:37 +0000246 try:
mbligh31260692008-04-16 23:12:12 +0000247 ## Unfortunately, we can not request reasons of failure always
248 ## because it may result in an inflated size of data transfer
249 ## (at the moment we fetch 500 bytes of reason descriptions into
250 ## each cell )
251 ## If 'status' in [row,column] then either width or height
252 ## of the table <=7, hence table is not really 2D, and
253 ## query_reason is relatively save.
254 ## At the same time view when either rows or columns grouped
255 ## by status is when users need reasons of failures the most.
256
257 ## TO DO: implement [Show/Hide reasons] button or link in
258 ## all views and make thorough performance testing
259 test_data = frontend.get_matrix_data(db_obj, column, row, where,
260 query_reasons = ('status' in [row,column])
261 )
mblighaea09602008-04-16 22:59:37 +0000262 except db.MySQLTooManyRows, error:
263 return [[display.box(str(error))]]
mbligh44710b62008-03-07 00:25:43 +0000264
mbligh439661b2008-02-19 15:57:53 +0000265 for f_row in force_row:
266 if not f_row in test_data.y_values:
267 test_data.y_values.append(f_row)
268 for f_column in force_column:
269 if not f_column in test_data.x_values:
270 test_data.x_values.append(f_column)
mbligh2e4e5df2007-11-05 17:22:46 +0000271
mbligh2ba3e732008-01-16 01:30:19 +0000272 if not test_data.y_values:
mbligh12eebfa2008-01-03 02:01:53 +0000273 msg = "There are no results for this query (yet?)."
274 return [[display.box(msg)]]
mbligh2e4e5df2007-11-05 17:22:46 +0000275
mbligh456b4772008-03-25 23:54:45 +0000276 dict_url = {'columns': row,
mblighbe257452008-04-16 23:29:13 +0000277 'rows': column, 'condition': condition_field,
278 'title': title_field}
mbligh456b4772008-03-25 23:54:45 +0000279 link = 'compose_query.cgi?' + urllib.urlencode(dict_url)
mbligh5dd503b2008-01-03 16:35:27 +0000280 header_row = [display.box("<center>(Flip Axis)</center>", link=link)]
281
mbligh2ba3e732008-01-16 01:30:19 +0000282 for x in test_data.x_values:
apw7a7316b2008-02-21 17:42:05 +0000283 dx = x
284 if field_map.has_key(column):
285 dx = field_map[column](x)
mbligh44710b62008-03-07 00:25:43 +0000286 x_header = header_tuneup(column, dx)
287 link = construct_link(x, None)
288 header_row.append(display.box(x_header,header=True,link=link))
mbligh2e4e5df2007-11-05 17:22:46 +0000289
290 matrix = [header_row]
mbligh2ba3e732008-01-16 01:30:19 +0000291 for y in test_data.y_values:
apw7a7316b2008-02-21 17:42:05 +0000292 dy = y
293 if field_map.has_key(row):
294 dy = field_map[row](y)
mbligh44710b62008-03-07 00:25:43 +0000295 y_header = header_tuneup(row, dy)
mbligh5bb55862008-04-16 23:09:31 +0000296 link = construct_link(None, y)
mbligh44710b62008-03-07 00:25:43 +0000297 cur_row = [display.box(y_header, header=True, link=link)]
mbligh2ba3e732008-01-16 01:30:19 +0000298 for x in test_data.x_values:
mbligh44710b62008-03-07 00:25:43 +0000299 ## next 2 lines: temporary, until non timestamped
300 ## records are in the database
301 if x==datetime.datetime(1970,1,1): x = None
302 if y==datetime.datetime(1970,1,1): y = None
mbligh12eebfa2008-01-03 02:01:53 +0000303 try:
mbligh31260692008-04-16 23:12:12 +0000304 box_data = test_data.data[x][y]
mbligh12eebfa2008-01-03 02:01:53 +0000305 except:
306 cur_row.append(display.box(None, None))
307 continue
mbligh2ba3e732008-01-16 01:30:19 +0000308 job_tag = test_data.data[x][y].job_tag
mbligh5dd503b2008-01-03 16:35:27 +0000309 if job_tag:
mblighe47ff2a2008-02-28 00:44:11 +0000310 link = frontend.html_root + job_tag + '/'
mbligh439661b2008-02-19 15:57:53 +0000311 if (row == 'test' and
312 not 'boot' in y and
313 not 'build' in y and
314 not 'install' in y ):
315 link += y + '/'
316 if (column == 'test' and
317 not 'boot' in x and
318 not 'build' in x and
319 not 'install' in x):
320 link += x + '/'
mbligh5dd503b2008-01-03 16:35:27 +0000321 else:
mbligh2ba3e732008-01-16 01:30:19 +0000322 link = construct_link(x, y)
mbligh44710b62008-03-07 00:25:43 +0000323
mblighaea09602008-04-16 22:59:37 +0000324 cur_row.append(display.status_precounted_box(db_obj,
mbligh5dd503b2008-01-03 16:35:27 +0000325 box_data,
326 link))
mbligh12eebfa2008-01-03 02:01:53 +0000327 matrix.append(cur_row)
mbligh12eebfa2008-01-03 02:01:53 +0000328 return matrix
mbligh2b672532007-11-05 19:24:51 +0000329
mbligh2b672532007-11-05 19:24:51 +0000330
mbligh12eebfa2008-01-03 02:01:53 +0000331def main():
mbligh190a81d2007-11-05 20:40:38 +0000332 # create the actual page
mbligh190a81d2007-11-05 20:40:38 +0000333 print '<html><head><title>'
334 print 'Filtered Autotest Results'
335 print '</title></head><body>'
mbligh14671622008-01-11 16:49:54 +0000336 display.print_main_header()
mbligh2ba3e732008-01-16 01:30:19 +0000337 print html_header % (create_select_options(column),
338 create_select_options(row),
mblighbe257452008-04-16 23:29:13 +0000339 condition_field, title_field)
340 if title_field:
341 print '<h1> %s </h1>' % (title_field)
mbligh439661b2008-02-19 15:57:53 +0000342 print display.color_keys_row()
mbligh12eebfa2008-01-03 02:01:53 +0000343 display.print_table(gen_matrix())
mbligh439661b2008-02-19 15:57:53 +0000344 print display.color_keys_row()
mbligh190a81d2007-11-05 20:40:38 +0000345 print '</body></html>'
mbligh2e4e5df2007-11-05 17:22:46 +0000346
347
348main()