1/* 2 * Copyright (c) 2015-2017, John R. Marino <draco@marino.st> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16var SbInterval = 10; 17var progwidth = 950; 18var progheight = 14; 19var progtop = 2; 20var run_active; 21var kfiles = 0; 22var last_kfile = 1; 23var history = [[]]; 24 25/* Disabling jQuery caching */ 26$.ajaxSetup({ 27 cache: false 28}); 29 30function catwidth (variable, queued) { 31 if (variable == 0) 32 return 0; 33 var width = variable * progwidth / queued; 34 return (width < 1) ? 1 : Math.round (width); 35} 36 37function maxcatwidth(A, B, C, D, queued) { 38 var cat = new Array(); 39 cat[0] = catwidth (A, queued); 40 cat[1] = catwidth (B, queued); 41 cat[2] = catwidth (C, queued); 42 cat[3] = catwidth (D, queued); 43 cat.sort(function(a,b){return a-b}); 44 return (progwidth - cat[0] - cat[1] - cat[2]); 45} 46 47function minidraw(x, context, color, queued, variable, mcw) { 48 var width = catwidth (variable, queued); 49 if (width == 0) 50 return (0); 51 if (width > mcw) 52 width = mcw; 53 context.fillStyle = color; 54 context.fillRect(x, progtop + 1, width, progheight + 2); 55 return (width); 56} 57 58function update_canvas(stats) { 59 var queued = stats.queued; 60 var built = stats.built; 61 var meta = stats.meta; 62 var failed = stats.failed; 63 var skipped = stats.skipped; 64 var ignored = stats.ignored; 65 66 var canvas = document.getElementById('progressbar'); 67 if (canvas.getContext === undefined) { 68 /* Not supported */ 69 return; 70 } 71 72 var context = canvas.getContext('2d'); 73 74 context.fillStyle = '#D8D8D8'; 75 context.fillRect(0, progtop + 1, progwidth, progheight + 2); 76 var x = 0; 77 var mcw = maxcatwidth (built, meta, failed, ignored, skipped, queued); 78 x += minidraw(x, context, "#339966", queued, built, mcw); 79 x += minidraw(x, context, "#A577E1", queued, meta, mcw); 80 x += minidraw(x, context, "#CC0033", queued, failed, mcw); 81 x += minidraw(x, context, "#FFCC33", queued, ignored, mcw); 82 x += minidraw(x, context, "#CC6633", queued, skipped, mcw); 83} 84 85function filter (txt) { 86 $('#report input').val (txt).trigger('search'); 87} 88 89function process_summary(data) { 90 var html; 91 var RB = '<tr>'; 92 var RE = '</tr>'; 93 var B = '<td>'; 94 var E = '</td>'; 95 96 kfiles = parseInt (data.kfiles); 97 run_active = parseInt (data.active); 98 $('#profile').html(data.profile); 99 $('#kickoff').html(data.kickoff); 100 $('#polling').html(run_active ? "Active" : "Complete"); 101 if (data.stats) { 102 $.each(data.stats, function(status, count) { 103 html = count; 104 $('#stats_' + status).html(html); 105 }); 106 update_canvas (data.stats); 107 } 108 109 $('#builders_body tbody').empty(); 110 for (n = 0; n < data.builders.length; n++) { 111 var trow = RB + '<td class="b' + data.builders[n].ID + 112 '" onclick="filter(\'[' + data.builders[n].ID + 113 ']\')" title="Click to filter for work done by builder ' + 114 data.builders[n].ID + '">' 115 + data.builders[n].ID + E + 116 B + data.builders[n].elapsed + E + 117 B + data.builders[n].phase + E + 118 B + data.builders[n].origin + E + 119 B + data.builders[n].lines + E + 120 RE; 121 $('#builders_body tbody').append (trow); 122 } 123} 124 125function digit2(n){ 126 return n > 9 ? "" + n: "0" + n; 127} 128 129function logfile (origin) { 130 var parts = origin.split('/'); 131 return '../' + parts[0] + '___' + parts[1] + '.log'; 132} 133 134function format_result (result) { 135 return '<div class="' + result + ' result">' + result + '<div>'; 136} 137 138function format_entry (entry, origin) { 139 return '<span class="entry" onclick="filter(\'' + origin+ '\')">' + 140 entry + '</span>'; 141} 142 143function information (result, origin, info) { 144 var parts; 145 if (result == "meta") { 146 return 'meta-node complete.'; 147 } else if (result == "built") { 148 return '<a href="' + logfile (origin) + '">logfile</a>'; 149 } else if (result == "failed") { 150 parts = info.split(':'); 151 return 'Failed ' + parts[0] + ' phase (<a href="' + logfile (origin) + 152 '">logfile</a>)'; 153 } else if (result == "skipped") { 154 return 'Issue with ' + info; 155 } else if (result == "ignored") { 156 parts = info.split(':|:'); 157 return parts[0]; 158 } else { 159 return "??"; 160 } 161} 162 163function skip_info (result, info) { 164 var parts; 165 if (result == "failed") { 166 parts = info.split(':'); 167 return parts[1]; 168 } else if (result == "ignored") { 169 parts = info.split(':|:'); 170 return parts[1]; 171 } else { 172 return ""; 173 } 174} 175 176function portsmon (origin) { 177 var parts = origin.split('/'); 178 var FPClink = '<a title="portsmon for "' + origin + '" href="http://portsmon.freebsd.org/portoverview.py?category=' + parts[0] + '&portname=' + parts[1] + '">' + origin + '</a>'; 179 var NPSlink = '<a title="pkgsrc.se overview" href="http://pkgsrc.se/' + origin + '">' + origin + '</a>'; 180 return FPClink; 181} 182 183function process_history_file(data, k) { 184 history [k] = []; 185 for (n = 0; n < data.length; n++) { 186 var trow = []; 187 trow.push(format_entry (data[n].entry, data[n].origin)); 188 trow.push(data[n].elapsed); 189 trow.push('[' + data[n].ID + ']'); 190 trow.push(format_result (data[n].result)); 191 trow.push(portsmon (data[n].origin)); 192 trow.push(information (data[n].result, data[n].origin, data[n].info)); 193 trow.push(skip_info (data[n].result, data[n].info)); 194 trow.push(data[n].duration); 195 history [k].push (trow); 196 } 197} 198 199function cycle () { 200 if (run_active) { 201 setTimeout(update_summary_and_builders, SbInterval * 1000); 202 } else { 203 $('#builders_zone_2').fadeOut(2500); 204 $('#main').css('border-top', '1px solid #404066'); 205 } 206} 207 208function update_history_success(kfile) { 209 if (kfile == kfiles) { 210 var full_history = []; 211 for (var k = 1; k <= kfiles; k++) { 212 full_history = full_history.concat (history[k]); 213 } 214 $('#report_table').dataTable().fnClearTable(); 215 $('#report_table').dataTable().fnAddData(full_history); 216 cycle(); 217 } else { 218 last_kfile = kfile + 1; 219 update_history(); 220 } 221} 222 223function update_history() { 224 if (kfiles == 0) { 225 cycle(); 226 return; 227 } 228 clearInterval(update_history); 229 $.ajax({ 230 url: digit2(last_kfile) + '_history.json', 231 dataType: 'json', 232 success: function(data) { 233 process_history_file(data, last_kfile); 234 update_history_success (last_kfile); 235 }, 236 error: function(data) { 237 /* May not be there yet, try again shortly */ 238 setTimeout(update_history, SbInterval * 500); 239 } 240 }) 241} 242 243function update_summary_and_builders() { 244 $.ajax({ 245 url: 'summary.json', 246 dataType: 'json', 247 success: function(data) { 248 process_summary(data); 249 clearInterval(update_summary_and_builders); 250 update_history(); 251 }, 252 error: function(data) { 253 /* May not be there yet, try again shortly */ 254 setTimeout(update_summary_and_builders, SbInterval * 500); 255 } 256 }); 257} 258 259$(document).ready(function() { 260 261 $('#report_table').dataTable({ 262 "aaSorting": [[ 0, 'desc' ]], 263 "bProcessing": true, // Show processing icon 264 "bDeferRender": true, // Defer creating TR/TD until needed 265 "aoColumnDefs": [ 266 {"bSortable": false, "aTargets": [1,2,3,5]}, 267 {"bSearchable": false, "aTargets": [0,1,6,7]}, 268 ], 269 "bStateSave": true, // Enable cookie for keeping state 270 "aLengthMenu":[10,20,50, 100, 200], 271 "iDisplayLength": 20, 272 }); 273 274 update_summary_and_builders(); 275}) 276 277$(document).bind("keydown", function(e) { 278 /* Disable F5 refreshing since this is AJAX driven. */ 279 if (e.which == 116) { 280 e.preventDefault(); 281 } 282}); 283