diff --git a/get-b2gcrashes.php b/get-b2gcrashes.php index b02f422..d834ffa 100755 --- a/get-b2gcrashes.php +++ b/get-b2gcrashes.php @@ -94,6 +94,7 @@ for ($daysback = $backlog_days + 1; $daysback > 0; $daysback--) { $fbtc = 'b2g-topcrashes.json'; $fpages = 'pages.json'; $fweb = $anadir.'.b2g.crashes.html'; + $fwebweek = $anadir.'.b2g.topcrashes.weekly.html'; $anafbcdata = $anadir.'/'.$fbcdata; if (!file_exists($anafbcdata)) { @@ -147,6 +148,8 @@ for ($daysback = $backlog_days + 1; $daysback > 0; $daysback--) { $bcd['total']++; } + uasort($bcd['list'], 'b2glist_compare'); // sort by B2G version, build ID, and crash time + file_put_contents($anafbcdata, json_encode($bcd)); } else { @@ -157,15 +160,14 @@ for ($daysback = $backlog_days + 1; $daysback > 0; $daysback--) { if (!file_exists($anafbtc)) { $btc = array(); foreach ($bcd['list'] as $crash) { - $report = $crash['version'].'::'.$crash['release_channel'].'::'.$crash['b2g_ver']; + $b2g_ver = strlen($crash['b2g_ver'])?$crash['b2g_ver']:'unknown'; + $report = $b2g_ver; $device = strlen($crash['device'])?$crash['device']:'unknown'; $buildday = substr($crash['build'], 0, 8); $ptype = strlen($crash['process_type'])?$crash['process_type']:'gecko'; addCount($btc, $report); if ($btc[$report]['.count'] == 1) { - $btc[$report]['version'] = $crash['version']; - $btc[$report]['release_channel'] = $crash['release_channel']; - $btc[$report]['b2g_ver'] = $crash['b2g_ver']; + $btc[$report]['b2g_ver'] = $b2g_ver; $btc[$report]['.sigs'] = array(); } addCount($btc[$report]['.sigs'], $crash['signature']); @@ -198,7 +200,7 @@ for ($daysback = $backlog_days + 1; $daysback > 0; $daysback--) { } } - krsort($btc); // sort by key (version::channel) in reverse order + krsort($btc); // sort by key (b2g_ver) in reverse order foreach ($btc as $report=>$rdata) { if (array_key_exists('.sigs', $rdata)) { uasort($btc[$report]['.sigs'], 'count_compare'); // sort by count, highest-first @@ -216,293 +218,363 @@ for ($daysback = $backlog_days + 1; $daysback > 0; $daysback--) { $btc = json_decode(file_get_contents($anafbtc), true); } - $anafweb = $anadir.'/'.$fweb; - if (!file_exists($anafweb) && - count($bcd) && $bcd['total']) { - // create out an HTML page - print('Writing HTML output'."\n"); - $doc = new DOMDocument('1.0', 'utf-8'); - $doc->formatOutput = true; // we want a nice output + $webreports = array('day' => $fweb, 'week' => $fwebweek); - $root = $doc->appendChild($doc->createElement('html')); - $head = $root->appendChild($doc->createElement('head')); - $title = $head->appendChild($doc->createElement('title', - $anadir.' B2G Crashes Report')); + foreach ($webreports as $type=>$fwebcur) { + $anafweb = $anadir.'/'.$fwebcur; + if ($type == 'week') { + if (!file_exists($anafweb)) { + // assemble 7-day "weekly" overview + print('Calculating weekly data'."\n"); + $curbtc = $btc; - $style = $head->appendChild($doc->createElement('style')); - $style->setAttribute('type', 'text/css'); - $style->appendChild($doc->createCDATASection( - 'body {'."\n" - .' color: #000000;'."\n" - .' background-color: #FFFFFF;'."\n" - .'}'."\n" - .'.sig, .time {'."\n" - .' font-size: small;'."\n" - .'}'."\n" - .'.buildid > .timepart {'."\n" - .' color: #808080;'."\n" - .'}'."\n" - .'.device {'."\n" - .' color: #808080;'."\n" - .'}'."\n" - .'/* Shipped devices */'."\n" - .'.device.zte_roamer2,'."\n" - .'.device.unknown_alcatel_one_touch_fire {'."\n" - .' color: #000000;'."\n" - .' font-weight: bold;'."\n" - .'}'."\n" - .'/* Internal testing devices */'."\n" - .'.device.toro_unagi1,'."\n" - .'.device.toro_otoro1,'."\n" - .'.device.toro_inari1,'."\n" - .'.device.qcom_leo {'."\n" - .' color: #000000;'."\n" - .' font-style: italic;'."\n" - .'}'."\n" - .'/* Developer devices */'."\n" - .'.device.geeksphone_gp_peak,'."\n" - .'.device.geeksphone_gp_keon,'."\n" - .'.device.geeksphone_gp_twist {'."\n" - .' color: #000000;'."\n" - .'}'."\n" - .'.ptype.gecko {'."\n" - .'}'."\n" - .'.ptype.content {'."\n" - .' color: #808080;'."\n" - .'}'."\n" - .'.bug {'."\n" - .' font-size: small;'."\n" - .' empty-cells: show;'."\n" - .'}'."\n" - .'.resolved {'."\n" - .' text-decoration: line-through;'."\n" - .'}'."\n" - .'.num, .pct {'."\n" - .' text-align: right;'."\n" - .'}'."\n" - )); - - $body = $root->appendChild($doc->createElement('body')); - $h1 = $body->appendChild($doc->createElement('h1', - $anadir.' B2G Crashes Report')); - - $list = $body->appendChild($doc->createElement('ul')); - $item = $list->appendChild($doc->createElement('li')); - $link = $item->appendChild($doc->createElement('a', - 'Top Crashes By Signature')); - $link->setAttribute('href', '#tcbs'); - $tlist = $item->appendChild($doc->createElement('ul')); - foreach ($btc as $report=>$rdata) { - $titem = $tlist->appendChild($doc->createElement('li')); - $tlink = $titem->appendChild($doc->createElement('a', - $rdata['version'].' '.$rdata['release_channel'].' ('.$rdata['b2g_ver'].')')); - $tlink->setAttribute('href', '#'.$rdata['version'].$rdata['release_channel'].'-'.$rdata['b2g_ver']); + for ($pastday = 1; $pastday < 7; $pastday++) { + $pasttime = strtotime($anadir.' -'.$pastday.' day'); + $pastdir = date('Y-m-d', $pasttime); + print('Adding '.$pastdir); + $pastfbtc = $pastdir.'/'.$fbtc; + if (file_exists($pastfbtc)) { + // Load that data and merge it into $curcd. + $pastbtc = json_decode(file_get_contents($pastfbtc), true); + foreach ($pastbtc as $report=>$rdata) { + print(':'); + if (array_key_exists($report, $curbtc)) { + $curbtc[$report]['.count'] += $rdata['.count']; + foreach ($rdata['.sigs'] as $sig=>$sdata) { + print('.'); + if (array_key_exists($sig, $curbtc[$report]['.sigs'])) { + $curbtc[$report]['.sigs'][$sig]['.count'] += $sdata['.count']; + $curbtc[$report]['.sigs'][$sig]['devices'] = + array_unique(array_merge($curbtc[$report]['.sigs'][$sig]['devices'], $sdata['devices'])); + $curbtc[$report]['.sigs'][$sig]['bdates'] = + array_unique(array_merge($curbtc[$report]['.sigs'][$sig]['bdates'], $sdata['bdates'])); + $curbtc[$report]['.sigs'][$sig]['proctypes'] = + array_unique(array_merge($curbtc[$report]['.sigs'][$sig]['proctypes'], $sdata['proctypes'])); + } + else { + $curbtc[$report]['.sigs'][$sig] = $sdata; + } + } + } + else { + print('.'); + $curbtc[$report] = $rdata; + } + } + print("\n"); + } + else { print(' - '.$pastfbtc.' not found.'."\n"); } + } + if (count($curbtc)) { + krsort($curbtc); // sort by key (b2g_ver) in reverse order + foreach ($curbtc as $report=>$rdata) { + if (array_key_exists('.sigs', $rdata)) { + uasort($curbtc[$report]['.sigs'], 'count_compare'); // sort by count, highest-first + foreach ($rdata['.sigs'] as $sig=>$sdata) { + sort($curbtc[$report]['.sigs'][$sig]['devices']); + rsort($curbtc[$report]['.sigs'][$sig]['bdates']); + sort($curbtc[$report]['.sigs'][$sig]['proctypes']); + } + } + } + } + } + } + else { + // single-day data + $curbtc = $btc; } - $list = $body->appendChild($doc->createElement('ul')); - $item = $list->appendChild($doc->createElement('li')); - $link = $item->appendChild($doc->createElement('a', - 'Raw Crash List')); - $link->setAttribute('href', '#crashlist'); - $h2 = $body->appendChild($doc->createElement('h2', - 'Top Crashes By Signature')); - $link->setAttribute('id', 'tcbs'); + if (!file_exists($anafweb) && count($curbtc)) { + // create out an HTML page + print('Writing HTML output'."\n"); + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; // we want a nice output - foreach ($btc as $report=>$rdata) { - $h3 = $body->appendChild($doc->createElement('h3', - $rdata['version'].' '.$rdata['release_channel'].' ('.$rdata['b2g_ver'].')')); - $link->setAttribute('id', $rdata['version'].$rdata['release_channel'].'-'.$rdata['b2g_ver']); + $root = $doc->appendChild($doc->createElement('html')); + $head = $root->appendChild($doc->createElement('head')); + $title = $head->appendChild($doc->createElement('title', + $anadir.($type == 'week'?' Weekly':'').' B2G Crashes Report')); - $table = $body->appendChild($doc->createElement('table')); - $table->setAttribute('border', '1'); + $style = $head->appendChild($doc->createElement('style')); + $style->setAttribute('type', 'text/css'); + $style->appendChild($doc->createCDATASection('' + .'body {'."\n" + .' color: #000000;'."\n" + .' background-color: #FFFFFF;'."\n" + .'}'."\n" + .'.sig, .time {'."\n" + .' font-size: small;'."\n" + .'}'."\n" + .'.buildid > .timepart {'."\n" + .' color: #808080;'."\n" + .'}'."\n" + .'.device {'."\n" + .' color: #808080;'."\n" + .'}'."\n" + .'/* Shipped devices */'."\n" + .'.device.zte_roamer2,'."\n" + .'.device.unknown_alcatel_one_touch_fire {'."\n" + .' color: #000000;'."\n" + .' font-weight: bold;'."\n" + .'}'."\n" + .'/* Internal testing devices */'."\n" + .'.device.toro_unagi1,'."\n" + .'.device.toro_otoro1,'."\n" + .'.device.toro_inari1,'."\n" + .'.device.qcom_leo,'."\n" + .'.device.lge_lg_d300 {'."\n" + .' color: #000000;'."\n" + .' font-style: italic;'."\n" + .'}'."\n" + .'/* Developer devices */'."\n" + .'.device.geeksphone_gp_peak,'."\n" + .'.device.geeksphone_gp_keon,'."\n" + .'.device.geeksphone_gp_twist {'."\n" + .' color: #000000;'."\n" + .'}'."\n" + .'.ptype.gecko {'."\n" + .'}'."\n" + .'.ptype.content {'."\n" + .' color: #808080;'."\n" + .'}'."\n" + .'.bug {'."\n" + .' font-size: small;'."\n" + .' empty-cells: show;'."\n" + .'}'."\n" + .'.resolved {'."\n" + .' text-decoration: line-through;'."\n" + .'}'."\n" + .'.num, .pct {'."\n" + .' text-align: right;'."\n" + .'}'."\n" + )); - // table head - $tr = $table->appendChild($doc->createElement('tr')); - $th = $tr->appendChild($doc->createElement('th', 'Signature')); - $th = $tr->appendChild($doc->createElement('th', 'Devices')); - $th = $tr->appendChild($doc->createElement('th', 'Build Dates')); - $th = $tr->appendChild($doc->createElement('th', 'Process Types')); - $th = $tr->appendChild($doc->createElement('th', 'Count')); - $th = $tr->appendChild($doc->createElement('th', 'Pct')); - $th = $tr->appendChild($doc->createElement('th', 'Bugs')); + $body = $root->appendChild($doc->createElement('body')); + $h1 = $body->appendChild($doc->createElement('h1', + $anadir.($type == 'week'?' Weekly':'').' B2G Crashes Report')); - foreach ($rdata['.sigs'] as $sig=>$sdata) { - $pct = $rdata['.count'] ? - $sdata['.count'] / $rdata['.count'] : 0; + $list = $body->appendChild($doc->createElement('ul')); + $item = $list->appendChild($doc->createElement('li')); + $link = $item->appendChild($doc->createElement('a', + 'Top Crashes By Signature')); + $link->setAttribute('href', '#tcbs'); + $tlist = $item->appendChild($doc->createElement('ul')); + foreach ($curbtc as $report=>$rdata) { + $titem = $tlist->appendChild($doc->createElement('li')); + $tlink = $titem->appendChild($doc->createElement('a', + $rdata['b2g_ver'])); + $tlink->setAttribute('href', '#b2g-'.$rdata['b2g_ver']); + } + if ($type != 'week') { + $item = $list->appendChild($doc->createElement('li')); + $link = $item->appendChild($doc->createElement('a', + 'Raw Crash List')); + $link->setAttribute('href', '#crashlist'); + } + $h2 = $body->appendChild($doc->createElement('h2', + 'Top Crashes By Signature')); + $link->setAttribute('id', 'tcbs'); + + foreach ($curbtc as $report=>$rdata) { + $h3 = $body->appendChild($doc->createElement('h3', + $rdata['b2g_ver'])); + $link->setAttribute('id', 'b2g-'.$rdata['b2g_ver']); + + $table = $body->appendChild($doc->createElement('table')); + $table->setAttribute('border', '1'); + + // table head $tr = $table->appendChild($doc->createElement('tr')); - $td = $tr->appendChild($doc->createElement('td')); - $td->setAttribute('class', 'sig'); - if (!strlen($sig)) { - $link = $td->appendChild($doc->createElement('a', '(empty signature)')); - $link->setAttribute('href', $url_nullsiglink); - } - elseif ($sig == '\N') { - $td->appendChild($doc->createTextNode('(processing failure - "'.$sig.'")')); - } - else { - // common case, useful signature - $sigdisplay = preg_replace('/_+\.*$/', '', $sig); - $link = $td->appendChild($doc->createElement('a', - htmlentities($sigdisplay, ENT_COMPAT, 'UTF-8'))); - $link->setAttribute('href', $url_siglinkbase.rawurlencode($sig)); - } - $td = $tr->appendChild($doc->createElement('td')); - foreach ($sdata['devices'] as $device) { - if (strlen($td->textContent)) { - $td->appendChild($doc->createTextNode(', ')); + $th = $tr->appendChild($doc->createElement('th', 'Signature')); + $th = $tr->appendChild($doc->createElement('th', 'Devices')); + $th = $tr->appendChild($doc->createElement('th', 'Build Dates')); + $th = $tr->appendChild($doc->createElement('th', 'Process Types')); + $th = $tr->appendChild($doc->createElement('th', 'Count')); + $th = $tr->appendChild($doc->createElement('th', 'Pct')); + $th = $tr->appendChild($doc->createElement('th', 'Bugs')); + + foreach ($rdata['.sigs'] as $sig=>$sdata) { + $pct = $rdata['.count'] ? + $sdata['.count'] / $rdata['.count'] : 0; + + $tr = $table->appendChild($doc->createElement('tr')); + $td = $tr->appendChild($doc->createElement('td')); + $td->setAttribute('class', 'sig'); + if (!strlen($sig)) { + $link = $td->appendChild($doc->createElement('a', '(empty signature)')); + $link->setAttribute('href', $url_nullsiglink); } - $span = $td->appendChild($doc->createElement('span', $device)); - $span->setAttribute('class', 'device '.deviceClass($device)); - } - $td = $tr->appendChild($doc->createElement('td', implode(', ', $sdata['bdates']))); - $td = $tr->appendChild($doc->createElement('td')); - foreach ($sdata['proctypes'] as $ptype) { - if (strlen($td->textContent)) { - $td->appendChild($doc->createTextNode(', ')); + elseif ($sig == '\N') { + $td->appendChild($doc->createTextNode('(processing failure - "'.$sig.'")')); } - $span = $td->appendChild($doc->createElement('span', $ptype)); - $span->setAttribute('class', 'ptype '.$ptype); - } - $td = $tr->appendChild($doc->createElement('td', $sdata['.count'])); - $td->setAttribute('class', 'num'); - $td = $tr->appendChild($doc->createElement('td', - sprintf('%.1f', 100 * $pct).'%')); - $td->setAttribute('class', 'pct'); - $td = $tr->appendChild($doc->createElement('td')); - if (array_key_exists('bugs', $sdata) && count($sdata['bugs'])) { - foreach ($sdata['bugs'] as $bug => $bugdata) { + else { + // common case, useful signature + $sigdisplay = preg_replace('/_+\.*$/', '', $sig); + $link = $td->appendChild($doc->createElement('a', + htmlentities($sigdisplay, ENT_COMPAT, 'UTF-8'))); + $link->setAttribute('href', $url_siglinkbase.rawurlencode($sig)); + } + $td = $tr->appendChild($doc->createElement('td')); + foreach ($sdata['devices'] as $device) { if (strlen($td->textContent)) { $td->appendChild($doc->createTextNode(', ')); } - $link = $td->appendChild($doc->createElement('a', $bug)); - $link->setAttribute('href', $url_buglinkbase.$bug); - $link->setAttribute('title', - $bugdata['status'].' '.$bugdata['resolution'].' - ' - .htmlentities($bugdata['short_desc'], ENT_COMPAT, 'UTF-8')); - if ($bugdata['status'] == 'RESOLVED' || $bugdata['status'] == 'VERIFIED') { - $link->setAttribute('class', 'bug resolved'); - } - else { - $link->setAttribute('class', 'bug'); - } + $span = $td->appendChild($doc->createElement('span', $device)); + $span->setAttribute('class', 'device '.deviceClass($device)); } - } - else { - $td->appendChild($doc->createTextNode('-')); - } - } - } - - $h2 = $body->appendChild($doc->createElement('h2', - 'Raw Crash List')); - $link->setAttribute('id', 'crashlist'); - - // description - $para = $body->appendChild($doc->createElement('p', - 'List of all '.$bcd['total'].' crashes for B2G on actual devices.' - .' (Times in the "Crash" column are UTC and link to the detailed crash' - .' reports on Socorro.)')); - - $table = $body->appendChild($doc->createElement('table')); - $table->setAttribute('border', '1'); - - // table head - $tr = $table->appendChild($doc->createElement('tr')); - $th = $tr->appendChild($doc->createElement('th', 'Ver')); - $th = $tr->appendChild($doc->createElement('th', 'Build ID')); - $th = $tr->appendChild($doc->createElement('th', 'Channel')); - $th = $tr->appendChild($doc->createElement('th', 'B2G-Ver')); - $th = $tr->appendChild($doc->createElement('th', 'Crash')); - $th = $tr->appendChild($doc->createElement('th', 'Device')); - $th = $tr->appendChild($doc->createElement('th', 'Process')); - $th = $tr->appendChild($doc->createElement('th', 'Signature')); - $th = $tr->appendChild($doc->createElement('th', 'Bugs')); - - foreach ($bcd['list'] as $crash) { - $tr = $table->appendChild($doc->createElement('tr')); - $td = $tr->appendChild($doc->createElement('td', $crash['version'])); - $td->setAttribute('class', 'version'); - $td = $tr->appendChild($doc->createElement('td')); - $td->setAttribute('class', 'buildid'); - $span = $td->appendChild($doc->createElement('span', substr($crash['build'], 0, 8))); - $span->setAttribute('class', 'datepart'); - $span = $td->appendChild($doc->createElement('span', substr($crash['build'], 8))); - $span->setAttribute('class', 'timepart'); - $td = $tr->appendChild($doc->createElement('td', $crash['release_channel'])); - $td->setAttribute('class', 'channel'); - $td = $tr->appendChild($doc->createElement('td', $crash['b2g_ver'])); - $td->setAttribute('class', 'version'); - $td = $tr->appendChild($doc->createElement('td')); - $td->setAttribute('class', 'time'); - $link = $td->appendChild($doc->createElement('a', - gmdate('H:i:s', strtotime($crash['date_processed'])))); - $link->setAttribute('href', $url_replinkbase.$crash['uuid']); - $device = strlen($crash['device'])?$crash['device']:'unknown'; - $td = $tr->appendChild($doc->createElement('td', $device)); - $td->setAttribute('class', 'device '.deviceClass($device)); - $ptype = strlen($crash['process_type'])?$crash['process_type']:'gecko'; - $td = $tr->appendChild($doc->createElement('td', $ptype)); - $td->setAttribute('class', 'ptype '.$ptype); - $td = $tr->appendChild($doc->createElement('td')); - $td->setAttribute('class', 'sig'); - if (!strlen($crash['signature'])) { - $link = $td->appendChild($doc->createElement('a', '(empty signature)')); - $link->setAttribute('href', $url_nullsiglink); - } - elseif ($crash['signature'] == '\N') { - $td->appendChild($doc->createTextNode('(processing failure - "'.$crash['signature'].'")')); - } - else { - // common case, useful signature - $sigdisplay = preg_replace('/_+\.*$/', '', $crash['signature']); - $link = $td->appendChild($doc->createElement('a', - htmlentities($sigdisplay, ENT_COMPAT, 'UTF-8'))); - $link->setAttribute('href', $url_siglinkbase.rawurlencode($crash['signature'])); - } - $td = $tr->appendChild($doc->createElement('td')); - if (array_key_exists('bugs', $crash) && count($crash['bugs'])) { - foreach ($crash['bugs'] as $bug => $bugdata) { - if (strlen($td->textContent)) { - $td->appendChild($doc->createTextNode(', ')); + $td = $tr->appendChild($doc->createElement('td', implode(', ', $sdata['bdates']))); + $td = $tr->appendChild($doc->createElement('td')); + foreach ($sdata['proctypes'] as $ptype) { + if (strlen($td->textContent)) { + $td->appendChild($doc->createTextNode(', ')); + } + $span = $td->appendChild($doc->createElement('span', $ptype)); + $span->setAttribute('class', 'ptype '.$ptype); } - $link = $td->appendChild($doc->createElement('a', $bug)); - $link->setAttribute('href', $url_buglinkbase.$bug); - $link->setAttribute('title', - $bugdata['status'].' '.$bugdata['resolution'].' - ' - .htmlentities($bugdata['short_desc'], ENT_COMPAT, 'UTF-8')); - if ($bugdata['status'] == 'RESOLVED' || $bugdata['status'] == 'VERIFIED') { - $link->setAttribute('class', 'bug resolved'); + $td = $tr->appendChild($doc->createElement('td', $sdata['.count'])); + $td->setAttribute('class', 'num'); + $td = $tr->appendChild($doc->createElement('td', + sprintf('%.1f', 100 * $pct).'%')); + $td->setAttribute('class', 'pct'); + $td = $tr->appendChild($doc->createElement('td')); + if (array_key_exists('bugs', $sdata) && count($sdata['bugs'])) { + foreach ($sdata['bugs'] as $bug => $bugdata) { + if (strlen($td->textContent)) { + $td->appendChild($doc->createTextNode(', ')); + } + $link = $td->appendChild($doc->createElement('a', $bug)); + $link->setAttribute('href', $url_buglinkbase.$bug); + $link->setAttribute('title', + $bugdata['status'].' '.$bugdata['resolution'].' - ' + .htmlentities($bugdata['short_desc'], ENT_COMPAT, 'UTF-8')); + if ($bugdata['status'] == 'RESOLVED' || $bugdata['status'] == 'VERIFIED') { + $link->setAttribute('class', 'bug resolved'); + } + else { + $link->setAttribute('class', 'bug'); + } + } } else { - $link->setAttribute('class', 'bug'); + $td->appendChild($doc->createTextNode('-')); } } } - else { - $td->appendChild($doc->createTextNode('-')); + + if ($type != 'week') { + $h2 = $body->appendChild($doc->createElement('h2', + 'Raw Crash List')); + $link->setAttribute('id', 'crashlist'); + + // description + $para = $body->appendChild($doc->createElement('p', + 'List of all '.$bcd['total'].' crashes for B2G on actual devices.' + .' (Times in the "Crash" column are UTC and link to the detailed crash' + .' reports on Socorro.)')); + + $table = $body->appendChild($doc->createElement('table')); + $table->setAttribute('border', '1'); + + // table head + $tr = $table->appendChild($doc->createElement('tr')); + $th = $tr->appendChild($doc->createElement('th', 'B2G-Ver')); + $th = $tr->appendChild($doc->createElement('th', 'Build ID')); + $th = $tr->appendChild($doc->createElement('th', 'Ver')); + $th = $tr->appendChild($doc->createElement('th', 'Channel')); + $th = $tr->appendChild($doc->createElement('th', 'Crash')); + $th = $tr->appendChild($doc->createElement('th', 'Device')); + $th = $tr->appendChild($doc->createElement('th', 'Process')); + $th = $tr->appendChild($doc->createElement('th', 'Signature')); + $th = $tr->appendChild($doc->createElement('th', 'Bugs')); + + foreach ($bcd['list'] as $crash) { + $tr = $table->appendChild($doc->createElement('tr')); + $td = $tr->appendChild($doc->createElement('td', $crash['b2g_ver'])); + $td->setAttribute('class', 'version'); + $td = $tr->appendChild($doc->createElement('td')); + $td->setAttribute('class', 'buildid'); + $span = $td->appendChild($doc->createElement('span', substr($crash['build'], 0, 8))); + $span->setAttribute('class', 'datepart'); + $span = $td->appendChild($doc->createElement('span', substr($crash['build'], 8))); + $span->setAttribute('class', 'timepart'); + $td = $tr->appendChild($doc->createElement('td', $crash['version'])); + $td->setAttribute('class', 'version'); + $td = $tr->appendChild($doc->createElement('td', $crash['release_channel'])); + $td->setAttribute('class', 'channel'); + $td = $tr->appendChild($doc->createElement('td')); + $td->setAttribute('class', 'time'); + $link = $td->appendChild($doc->createElement('a', + gmdate('H:i:s', strtotime($crash['date_processed'])))); + $link->setAttribute('href', $url_replinkbase.$crash['uuid']); + $device = strlen($crash['device'])?$crash['device']:'unknown'; + $td = $tr->appendChild($doc->createElement('td', $device)); + $td->setAttribute('class', 'device '.deviceClass($device)); + $ptype = strlen($crash['process_type'])?$crash['process_type']:'gecko'; + $td = $tr->appendChild($doc->createElement('td', $ptype)); + $td->setAttribute('class', 'ptype '.$ptype); + $td = $tr->appendChild($doc->createElement('td')); + $td->setAttribute('class', 'sig'); + if (!strlen($crash['signature'])) { + $link = $td->appendChild($doc->createElement('a', '(empty signature)')); + $link->setAttribute('href', $url_nullsiglink); + } + elseif ($crash['signature'] == '\N') { + $td->appendChild($doc->createTextNode('(processing failure - "'.$crash['signature'].'")')); + } + else { + // common case, useful signature + $sigdisplay = preg_replace('/_+\.*$/', '', $crash['signature']); + $link = $td->appendChild($doc->createElement('a', + htmlentities($sigdisplay, ENT_COMPAT, 'UTF-8'))); + $link->setAttribute('href', $url_siglinkbase.rawurlencode($crash['signature'])); + } + $td = $tr->appendChild($doc->createElement('td')); + if (array_key_exists('bugs', $crash) && count($crash['bugs'])) { + foreach ($crash['bugs'] as $bug => $bugdata) { + if (strlen($td->textContent)) { + $td->appendChild($doc->createTextNode(', ')); + } + $link = $td->appendChild($doc->createElement('a', $bug)); + $link->setAttribute('href', $url_buglinkbase.$bug); + $link->setAttribute('title', + $bugdata['status'].' '.$bugdata['resolution'].' - ' + .htmlentities($bugdata['short_desc'], ENT_COMPAT, 'UTF-8')); + if ($bugdata['status'] == 'RESOLVED' || $bugdata['status'] == 'VERIFIED') { + $link->setAttribute('class', 'bug resolved'); + } + else { + $link->setAttribute('class', 'bug'); + } + } + } + else { + $td->appendChild($doc->createTextNode('-')); + } + } } - } - $doc->saveHTMLFile($anafweb); + $doc->saveHTMLFile($anafweb); - // add the page to the pages index - $anafpages = $anadir.'/'.$fpages; - if (file_exists($anafpages)) { - $pages = json_decode(file_get_contents($anafpages), true); + // add the page to the pages index + $anafpages = $anadir.'/'.$fpages; + if (file_exists($anafpages)) { + $pages = json_decode(file_get_contents($anafpages), true); + } + else { + $pages = array(); + } + $pages[$fweb] = + array('product' => 'B2G', + 'channel' => null, + 'version' => null, + 'report' => 'b2gcrash', + 'report_sub' => $type, + 'display_ver' => 'B2G', + 'display_rep' => 'Crashes Report'); + file_put_contents($anafpages, json_encode($pages)); } - else { - $pages = array(); - } - $pages[$fweb] = - array('product' => 'B2G', - 'channel' => null, - 'version' => null, - 'report' => 'b2gcrash', - 'report_sub' => null, - 'display_ver' => 'B2G', - 'display_rep' => 'Crashes Report'); - file_put_contents($anafpages, json_encode($pages)); } } print("\n"); @@ -515,6 +587,18 @@ function count_compare($a, $b) { return ($a['.count'] > $b['.count']) ? -1 : 1; } +// Comparison function on B2G version, build ID and time (reverse sort!) +function b2glist_compare($a, $b) { + if ($a['b2g_ver'] == $b['b2g_ver']) { + if ($a['build'] == $b['build']) { + if ($a['date_processed'] == $b['date_processed']) { return 0; } + return ($a['date_processed'] > $b['date_processed']) ? -1 : 1; + } + return ($a['build'] > $b['build']) ? -1 : 1; + } + return ($a['b2g_ver'] > $b['b2g_ver']) ? -1 : 1; +} + // Bump the counter of an element or initialize it. function addCount(&$basevar, $sub, $addnum = 1) { if (array_key_exists($sub, $basevar)) {