aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain d'Alverny <rda@mageia.org>2011-05-04 13:26:54 +0000
committerRomain d'Alverny <rda@mageia.org>2011-05-04 13:26:54 +0000
commitd08c07b68d0e88d863f597fe5e9ed72d84229ab7 (patch)
tree30b86dbcb4af35e87f2a76c637a214583022a0db
parent25cbfbccf63d176683a3da50913679cab311e21c (diff)
downloaddashboard-d08c07b68d0e88d863f597fe5e9ed72d84229ab7.tar
dashboard-d08c07b68d0e88d863f597fe5e9ed72d84229ab7.tar.gz
dashboard-d08c07b68d0e88d863f597fe5e9ed72d84229ab7.tar.bz2
dashboard-d08c07b68d0e88d863f597fe5e9ed72d84229ab7.tar.xz
dashboard-d08c07b68d0e88d863f597fe5e9ed72d84229ab7.zip
initial import
-rw-r--r--LICENSE.txt19
-rw-r--r--README.md47
-rw-r--r--Report/Box.php235
-rw-r--r--Report/Box/02_SourcePackage.php69
-rw-r--r--Report/Box/03_BuildSystem.php115
-rw-r--r--Report/Box/04_CauldronPackages.php146
-rw-r--r--Report/Box/ignore_01_UpstreamProjects.php49
-rw-r--r--Report/Box/ignore_05_CauldronISOBuild.php177
-rw-r--r--Report/HTML.php132
-rw-r--r--docs/mageia-dashboard-mockup-201102-rda.html266
-rw-r--r--make_report.php28
11 files changed, 1283 insertions, 0 deletions
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..fe16050
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Romain d'Alverny <rda@mageia.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a624597
--- /dev/null
+++ b/README.md
@@ -0,0 +1,47 @@
+# Dashboard for Mageia buildsystem
+Romain d'Alverny <rda> for Mageia.Org
+
+Code is available in http://svn.mageia.org/svn/soft/dashboard/
+under MIT license, see LICENSE.txt.
+
+## About
+
+This is quite an ugly functional sample to get a first idea of what
+we can have.
+
+Here, we focus on the chain from code source of individual projects to the
+final ISO to download:
+
+ - individual source projects (Box/01_UpstreamProjects.php, disabled for now)
+ - source packages in Mageia (Box/02_)
+ - build system (Box/03_)
+ - cauldron packages (Box/04_)
+ - ISO build (Box/5_, disabled for now)
+
+For each step, we aim to gather as meaningful data as possible: status, QA,
+availability, things broken or to improve.
+
+
+## Requirements
+
+ - PHP 5.2+
+
+
+## Usage
+
+Call make_report.php > report.html
+
+
+## Next
+
+Basically, in the future, we need:
+
+ * a service that fetches data from severals sources and normalize them
+ into a local data store; that doesn't prevent data sources to be published
+ in a practical form (say, UTF-8, json format, public API)
+
+ * a renderer (cron-called or on-the-fly) that publishes easy to grasp metrics
+ in visual forms.
+
+
+
diff --git a/Report/Box.php b/Report/Box.php
new file mode 100644
index 0000000..79408a0
--- /dev/null
+++ b/Report/Box.php
@@ -0,0 +1,235 @@
+<?php
+/**
+ * Abstract box class for reports.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+
+/**
+*/
+abstract class Report_Box
+{
+ /**
+ */
+ var $title = null;
+
+ /**
+ */
+ var $_new_values = null;
+
+ /**
+ */
+ var $working = false;
+
+ /**
+ */
+ function __construct()
+ {
+ $this->_labels = array_merge(array('?' => '%s %s'),
+ $this->_get_var_definitions());
+ }
+
+ /**
+ */
+ final public function run_report()
+ {
+ $path = realpath(dirname(__FILE__));
+ $files = glob(sprintf('%s/Box/*.php', $path));
+
+ foreach ($files as $f) {
+ if (substr(basename($f), 0, 7) != 'ignore_')
+ include $f;
+ }
+
+ $reports = array();
+ foreach (get_declared_classes() as $class) {
+ if (is_subclass_of($class, 'Report_Box')) {
+ echo $class, "\n";
+ $c = new $class;
+ $reports[] = $c->render();
+ }
+ }
+
+ file_put_contents('report.html', Report_HTML::render($reports));
+ }
+
+ /**
+ * lowercase keys!
+ */
+ final public function update()
+ {
+ $this->_get_new_values();
+ $this->_db_save($this->_new_values);
+ }
+
+ /**
+ */
+ function render ()
+ {
+ $this->load();
+
+ // associate key/values with string labels
+ // compute global statuts
+ // push
+ $status = count($this->_new_values);
+ $status_max = count($this->_new_values);
+ $links = $this->_get_links();
+ $values = array();
+
+ $this->_tmp_labels = $this->_labels;
+ if (is_null($this->_new_values))
+ $this->_new_values = array();
+
+ foreach ($this->_tmp_labels as $k => $v) {
+ //foreach ($this->_new_values as $k => $v) {
+ if ($k == '?')
+ continue;
+
+ $v = $this->_render_value_gen($k);
+
+ $status -= $v['s'];
+ $values[] = $v;
+ }
+
+ if (count($this->_tmp_labels) > 0) {
+ foreach ($this->_tmp_labels as $k => $v) {
+ if ($k == '?')
+ continue;
+
+ $values[] = $this->_render_value_gen($k);
+ }
+ }
+
+ echo $status / $status_max;
+
+ return array(
+ 'title' => $this->title,
+ 'status' => $status_max > 0 ? round($status / $status_max, 2) : 0,
+ 'values' => $values,
+ 'links' => $links
+ );
+ }
+
+ /**
+ */
+ final private function _render_value_gen($k = null)
+ {
+ if (array_key_exists($k, $this->_tmp_labels)) {
+
+ if ($this->_tmp_labels[$k] == ':render') {
+ $this->_cur_val = isset($this->_new_values[$k]) ? $this->_new_values[$k] : null;
+ $v = call_user_func(array($this, '_render_value_' . $k));
+ unset($this->_cur_val);
+ } else {
+ $v = $this->_render_value_default($k, $this->_tmp_labels[$k]);
+ }
+ } else {
+ $v = $this->_render_value_default($k);
+ }
+ unset($this->_tmp_labels[$k]);
+
+ return $v;
+ }
+
+ /**
+ */
+ final private function _render_value_default($k = null, $format = null)
+ {
+ $score = 0;
+ $class = 'unk';
+ $weight = 1;
+ $test_case = null;
+
+ if (is_null($format)) {
+ $format = '%s %s';
+ } elseif (!is_string($format)) {
+ $test_case = $format['t'];
+ $format = $format['l'];
+ $weight = isset($format['w']) ? $format['w'] : $weight;
+ }
+
+ $v = isset($this->_new_values[$k]) ? $this->_new_values[$k] : null;
+ if (!is_null($v)) {
+ if (!is_null($test_case)) {
+ $test_case = sprintf('$evalres = ($v %s);', $test_case);
+ eval($test_case);
+
+ $class = $evalres === true ? 'ok' : 'failed';
+ } else {
+ $class = 'ok';
+ }
+ } else {
+ $class = 'unk';
+ }
+
+ if ($class == 'failed')
+ $score = -1;
+ elseif ($class == 'ok')
+ $score = 1;
+
+ $score *= $weight;
+
+ return array(
+ 't' => sprintf($format, $v, $k),
+ 'c' => $class,
+ 's' => $score
+ );
+ }
+
+ /**
+ */
+ final public function load()
+ {
+ // go in table TABLE, load all most recent key/values
+ //
+ // TODO(rda)
+ $this->_get_new_values();
+ $this->_values = array();
+ }
+
+ /**
+ */
+ final private function _db_save($vals)
+ {
+ echo "Saving:\n";
+ echo get_class($this),"\n";
+ print_r($vals);
+ }
+
+ /**
+ */
+ final private function _get_new_values()
+ {
+ $values = null;
+ $methods = array();
+ foreach (get_class_methods($this) as $m) {
+ if (substr($m, 0, 7) == '_fetch_') {
+ $methods[] = $m;
+ }
+ }
+ if (count($methods) == 0) {
+ echo '> Nothing to fetch.', "\n";
+ } else {
+ $values = array();
+ foreach ($methods as $m) {
+ echo sprintf("> Calling [%s]", $m), "\n";
+ $values = array_merge($values, $this->$m());
+ }
+ }
+
+ $this->_new_values = $values;
+ }
+
+ /**
+ */
+ function _get_links()
+ {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/Report/Box/02_SourcePackage.php b/Report/Box/02_SourcePackage.php
new file mode 100644
index 0000000..9ba0039
--- /dev/null
+++ b/Report/Box/02_SourcePackage.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Source packages reporting box.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+
+/**
+*/
+class Report_Box_SourcePackage extends Report_Box
+{
+ /**
+ */
+ var $title = "Source packages";
+
+ /**
+ */
+ function _get_var_definitions() {
+ return array(
+ 'size' => '%5.1fGB',
+ 'count-srpms' => '%d packages',
+ 'upstream-updates' => array('l' => '%d have an update', 't' => '==0'),
+ 'orphans' => array('l' => '%d orphans', 't' => '>0'),
+ 'patches' => '%d patches',
+ 'bugs' => array('l' => '%d open bugs', 't' => '>0'),
+ 'rpmlint' => array('l' => '%d rpmlint errors', 't' => '>0'),
+ );
+ }
+
+ /**
+ */
+ function _get_links()
+ {
+ return 'View <a href="http://svn.mageia.org/">svn</a>, <a href="http://check.mageia.org/updates.html">youri-check report</a>';
+ }
+
+ /**
+ * Uses youri-check updates report (check.mageia.org)
+ */
+ function _fetch_upstream_updates()
+ {
+ $txt = file('http://check.mageia.org/updates.txt');
+ return array(
+ 'upstream-updates'=> count($txt) - 5
+ );
+ }
+
+ /**
+ * Uses sophie.zarb.org
+ */
+ function _fetch_source_packages()
+ {
+ $count = substr_count(
+ file_get_contents('http://sophie.zarb.org/distrib/Mageia/cauldron/i586/srpms?json=1'),
+ 'pkgid'
+ );
+
+ return array(
+ 'count-srpms' => $count,
+ );
+ }
+
+}
diff --git a/Report/Box/03_BuildSystem.php b/Report/Box/03_BuildSystem.php
new file mode 100644
index 0000000..b2d020d
--- /dev/null
+++ b/Report/Box/03_BuildSystem.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Buildsystem reporting box.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+/**
+*/
+class Report_Box_PackageBuildSystem extends Report_Box
+{
+ /**
+ */
+ var $title = "Packages Build <span class=\"light\">(past 48 hours)</span>";
+
+ /**
+ */
+ function _get_var_definitions() {
+ return array(
+ 'x_bs_queue_uploaded' => ':render', //'%d packages uploaded',
+ 'x_bs_queue_failure' => array('l' => '%d failed to build', 't' => '==0', 'w' => 0),
+ 'x_bs_queue_rejected' => array('l' => '%d rejected', 't' => '==0', 'w' => 0),
+ 'x_bs_buildtime' => ':render',
+ 'x_bs_buildtime_average' => ':render',
+ 'nodes' => ':render',
+ 'queue_size_avg' => 'queue size: 4/0/20',
+ 'wait_time' => 'wait time: 5/2/45'
+ );
+ }
+ /*
+ missing dependencies %
+ other
+ */
+
+ function _render_value_x_bs_buildtime()
+ {
+ return array(
+ 't' => sprintf('%5.2f hours of total buildtime<br />(%d%% of the time)',
+ $this->_cur_val / 60,
+ $this->_cur_val / 60 / 48 * 100
+ ),
+ 'c' => 'ok',
+ 's' => 0
+ );
+ }
+
+ function _render_value_x_bs_buildtime_average()
+ {
+ return array(
+ 't' => sprintf('%5.2f min of average buildtime', $this->_cur_val),
+ 'c' => 'ok',
+ 's' => 0
+ );
+ }
+
+ function _render_value_nodes()
+ {
+ return array(
+ 't' => '? nodes working fine out of ?',
+ 'c' => 'unk',
+ 's' => 0
+ );
+ }
+
+ function _render_value_x_bs_queue_uploaded()
+ {
+ return array(
+ 't' => sprintf('%d packages uploaded', $this->_cur_val),
+ 'c' => 'ok',
+ 's' => 0
+ );
+ }
+
+ /**
+ */
+ function _get_links()
+ {
+ return 'View <a href="http://pkgsubmit.mageia.org/">pkgsubmit</a>';
+ }
+
+ /**
+ * Fetch live report values from pkgsubmit HTTP headers,
+ * prefixed with X-BS-
+ *
+ * @return array
+ */
+ function _fetch_buildsystem()
+ {
+ $ret = array();
+ $h = get_headers('http://pkgsubmit.mageia.org/');
+ foreach ($h as $v)
+ {
+ $v = explode(':', trim($v));
+ if (substr($v[0], 0, 5) == 'X-BS-')
+ {
+ $k = str_replace('-', '_', strtolower($v[0]));
+ if (in_array($k, array(
+ 'x_bs_queue_todo',
+ 'x_bs_queue_building',
+ 'x_bs_queue_partial',
+ 'x_bs_queue_built',
+ 'x_bs_throttle'
+ )))
+ continue;
+ $ret[$k] = trim($v[1]);
+ }
+ }
+ return $ret;
+ }
+}
diff --git a/Report/Box/04_CauldronPackages.php b/Report/Box/04_CauldronPackages.php
new file mode 100644
index 0000000..c275f94
--- /dev/null
+++ b/Report/Box/04_CauldronPackages.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * Cauldron packages reporting box.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+
+/**
+*/
+class Report_Box_CauldronPackages extends Report_Box
+{
+ /**
+ */
+ var $title = "Cauldron Compiled Packages";
+
+ /**
+ */
+ function _get_var_definitions() {
+ return array(
+ 'size' => '%5.1fGB',
+ 'count-i586-rpms' => '%d packages (i586)',
+ 'count-x86_64-rpms' => '%d packages (x86_64)',
+ 'broken-pkgs' => array('l' => '%d have broken dependencies', 't' => '<=0'),
+ 'obs-bin' => array('l' => '%d obsolete binaries', 't' => '<=0'),
+ 'obs-source' => array('l' => '%d obsolete sources', 't' => '<=0'),
+ 'mis-source' => array('l' => '%d missing sources', 't' => '<=0'),
+ 'missing-deps' => array('l' => '%d missing dependencies', 't' => '<=0')
+ );
+ /*
+ ?GB
+ ? packages
+ Broken hdlist (i586/nonfree)
+ Signatures: 23 missing (i586/nonfree, i586/tainted)
+ Dependencies: 32 missing, 2 circular
+ 15 packages are not in sync with their source
+ 432 missing/broken signatures
+ 213 bugs
+ @todo: per package test suite? rpmlint, other
+ @todo: src => 32/64/arm
+ Basesystem size: 437MB, w/o suggests: 163MB
+ view repository, detailed report
+
+ */
+ }
+
+ /**
+ */
+ function _get_links()
+ {
+ return 'View <a href="http://check.mageia.org/">youri-check report</a>';
+ }
+
+
+ /**
+ * Uses youri-check report.
+ */
+ function _fetch_03_missing_dependencies()
+ {
+ $txt = file('http://check.mageia.org/missing.txt');
+ array_shift($txt);
+ array_shift($txt);
+ array_shift($txt);
+
+ $ret = array(
+ 'obs-source' => 0,
+ 'obs-bin' => 0,
+ 'mis-source' => 0
+ );
+ foreach ($txt as $l)
+ {
+ $l = explode("\t", $l);
+ if (!isset($l[3]) || !isset($l[5]))
+ continue;
+
+ $arch = trim($l[3]);
+ $reason = substr(trim($l[5]), 0, 14);
+ if ($arch == 'src') { //&& $l[5], 'Obsolete source')) {
+ $ret['obs-source'] += 1;
+ } elseif ($reason == 'Missing source') {
+ $ret['mis-source'] += 1;
+ } elseif ($reason == 'Obsolete binar') {
+ $ret['obs-bin'] += 1;
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Uses youri-check report.
+ */
+ function _fetch_02_broken_dependencies()
+ {
+ $txt = file('http://check.mageia.org/dependencies.txt');
+ array_shift($txt);
+ array_shift($txt);
+ array_shift($txt);
+
+ $package = null;
+
+ $reports = array();
+ foreach ($txt as $l)
+ {
+ $l = explode("\t", $l);
+ if (isset($l[0]) && isset($l[4])) {
+ $packages[] = trim($l[0]);
+ $missing[] = trim($l[4]);
+ }
+ }
+
+ $packages = array_unique($packages);
+ sort($packages);
+ $missing = array_unique($missing);
+ sort($missing);
+
+ return array(
+ 'broken-pkgs' => count($packages) - 1,
+ 'missing-deps' => count($missing) - 1
+ );
+ }
+
+ /**
+ * Uses sophie.zarb.org
+ */
+ function _fetch_01_packages()
+ {
+ $count_i586 = substr_count(
+ file_get_contents('http://sophie.zarb.org/distrib/Mageia/cauldron/i586/rpms?json=1'),
+ 'pkgid'
+ );
+ $count_x86_64 = substr_count(
+ file_get_contents('http://sophie.zarb.org/distrib/Mageia/cauldron/x86_64/rpms?json=1'),
+ 'pkgid'
+ );
+
+ return array(
+ 'count-i586-rpms' => $count_i586,
+ 'count-x86_64-rpms' => $count_x86_64
+ );
+ }
+}
diff --git a/Report/Box/ignore_01_UpstreamProjects.php b/Report/Box/ignore_01_UpstreamProjects.php
new file mode 100644
index 0000000..77f83cf
--- /dev/null
+++ b/Report/Box/ignore_01_UpstreamProjects.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Upstream projects source packages reporting box.
+ *
+ * Not working yet. Still a mockup.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+
+/**
+*/
+class Report_Box_UpstreamProjects extends Report_Box
+{
+ /**
+ */
+ var $title = "Upstream Projects";
+
+ /**
+ */
+ function _get_var_definitions() {
+ return array(
+ 'source-packages' => '%d source packages'
+ );
+ }
+
+ /**
+ */
+ function _get_links()
+ {
+ return 'View <a href="http://check.mageia.org/updates.html">detailed report (youri-check)</a>';
+ }
+
+ /**
+ * Uses youri-check updates report.
+ */
+ function _fetch_upstream_updates()
+ {
+ $txt = file('http://check.mageia.org/updates.txt');
+ return array(
+ 'upstream-updates'=> count($txt) - 5
+ );
+ }
+}
diff --git a/Report/Box/ignore_05_CauldronISOBuild.php b/Report/Box/ignore_05_CauldronISOBuild.php
new file mode 100644
index 0000000..254dcfb
--- /dev/null
+++ b/Report/Box/ignore_05_CauldronISOBuild.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * Cauldron ISO build service reporting box.
+ *
+ * Not working yet, mostly a mockup so far.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+
+/**
+*/
+class Report_Box_CauldronISOBuild extends Report_Box
+{
+ /**
+ */
+ var $title = "Cauldron ISO Build/QA/Pub";
+
+ /**
+ */
+ function _get_var_definitions() {
+ return array(
+ );
+ }
+
+ /**
+ */
+ function _get_links()
+ {
+ return 'View <a href="http://bcd.mageia.org/">bcd site</a>';
+ }
+
+ function render()
+ {
+ $obj = array(
+ array(
+ 'ts' => gmdate('c'),
+ 'type' => 'info',
+ 'value' => 'Built packages tree is not ready &ndash; no build planned.'
+ ),
+ array(
+ 'ts' => gmdate('c') - 5,
+ 'type' => 'info',
+ 'value' => 'Next build 1a1 should start in about 12 hours (at 2011-03-15 20:23:33), with a <a href="">new context</a>.'
+ ),
+ array(
+ 'ts' => gmdate('c') - 10,
+ 'type' => 'report',
+ 'build' => '1a0',
+ 'contextDiffLink' => '',
+ 'started_at' => '2011-03-14 23:03:15',
+ 'products' => array(
+ array(
+ 'name' => 'DVD i586',
+ 'build' => array(true, 'url'),
+ 'tests' => array(false, 'url'),
+ 'iso' => 'cauldron-2-dvd-i586-1a0-qafail.iso'
+ ),
+ array(
+ 'name' => 'DVD x86_64',
+ 'build' => array(true, 'url'),
+ 'tests' => array(true, 'url'),
+ 'iso' => 'cauldron-2-dvd-i586-1a0-qapass.iso'
+ ),
+ array(
+ 'name' => 'CD dual',
+ 'build' => array(false, 'url'),
+ 'tests' => null,
+ 'iso' => null
+ ),
+ array(
+ 'name' => 'netinstall',
+ 'build' => 'pending'
+ )
+ )
+ )
+ );
+ $values = array();
+ foreach ($obj as $item)
+ {
+ if ($item['type'] == 'info') {
+ $values[] = array(
+ 't' => sprintf('<p>%s</p>', $item['value']),
+ 'c' => null
+ );
+ }
+ elseif ($item['type'] == 'report') {
+ $lis = '';
+ foreach ($item['products'] as $p) {
+ $st = $item['build'][0] ? 'ok' : 'failed';
+ $lis .= <<<T
+<li>{$p['name']},
+ <span class="{$st}">build {$st}</span> (<a href="">log</a>),
+ <span class="{$st}">tests {$st}</span> (<a href="">log</a>),
+ <a href="">{$p['iso']}</a></li>
+T;
+ }
+ $text = <<<T
+<h4>Build {$item['build']}
+ <span style="font-weight: normal;">(<a href="">context diff w/ build {$item['prev_build']}</a>)</span>
+ &ndash; {$item['ts']}</h4>
+<ul>{$lis}</ul>
+T;
+ $values[] = array(
+ 't' => $text,
+ 'c' => null
+ );
+ }
+ }
+
+ return array(
+ 'title' => $this->title,
+ 'status' => 0,
+ 'values' => $values,
+ 'links' => $links
+ );
+ }
+/*
+ <li>DVD i586,
+ <span class="ok">build ok</span> (<a href="">log</a>),
+ <span class="failed">tests failed</span> (<a href="">log</a>),
+ <a href="">cauldron-2-dvd-i586-1a0-qafail.iso</a></li>
+ <li>DVD x86_64,
+ <span class="ok">build ok</span> (<a href="">log</a>),
+ <span class="ok">tests ok</span> (<a href="">log</a>),
+ <a href="">cauldron-2-dvd-i586-1a0-ok.iso</a></li>
+ <li>CD dual,
+ <span class="failed">build failed</span> (<a href="">log</a>)</li>
+ <li>building netinstall image...</li>
+ </ul>
+ <li><h4>Build 199
+ <span style="font-weight: normal;">(<a href="">context diff w/ build 198</a>)</span>
+ &ndash; 2011-03-12 23:03:15</h4>
+ <table border="1" class="isobuild">
+ <tbody>
+ <tr>
+ <th>Item</th>
+ <th>Build</th>
+ <th>Tests</th>
+ <th>Download</th>
+ </tr>
+ <tr>
+ <td>DVD i586</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><a href="">cauldron-2-1a0-dvd-i586-ok.iso</a></td>
+ </tr>
+ <tr>
+ <td>DVD x86_64</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><span class="failed">FAILED</span> (<a href="">log</a>)</td>
+ <td><a href="">cauldron-2-1a0-dvd-x86_64-qafail.iso</a></td>
+ </tr>
+ <tr>
+ <td>CD dual</td>
+ <td><span class="failed">FAILED</span> (<a href="">log</a>)</td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>netinstall</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><a href="">cauldron-2-1a0-netinstall-ok.iso</td>
+ </tr>
+ </tbody>
+ </table>
+
+ </li>
+ </ul>
+*/
+}
diff --git a/Report/HTML.php b/Report/HTML.php
new file mode 100644
index 0000000..6e27f14
--- /dev/null
+++ b/Report/HTML.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * HTML rendering box.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+
+/**
+*/
+class Report_HTML
+{
+
+ /**
+ *
+ */
+ function render($r)
+ {
+ $ret = '';
+ foreach ($r as $r1) {
+ $lis = '';
+ foreach ($r1['values'] as $v)
+ $lis .= sprintf('<li class="%s">%s</li>', $v['c'], $v['t']);
+
+ if ($r1['status'] >= 1)
+ $status = '<span class="ok">OK</span>';
+ elseif ($r1['status'] > 0.7)
+ $status = '<span class="good">GOOD</span>';
+ elseif ($r1['status'] < 0.5)
+ $status = '<span class="failed">NOT READY</span>';
+
+ $links = $r1['links'];
+ $ret .= <<<S
+<li class="{$working}"><h3>{$r1['title']}</h3>
+ <p>Status: {$status}</p>
+ <ul>{$lis}</ul>
+ <p>{$links}</p>
+</li>
+S;
+ }
+ $s = <<<S
+ <!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="robots" content="noindex,nosnippet,nocache,nofollow">
+ <title>Mageia buildsystem status overview</title>
+ <style>
+ body { font-size: 80%; font-family: Helvetica; background: #aaa; }
+ a:link, a:visited { color: #2383C2; text-decoration: none; }
+ .clear, hr { clear: both; }
+ ul.boxes { margin: 0; padding: 0; /*width: 1800px;*/ }
+ ul.boxes > li { padding-bottom: 2em; }
+ ul.boxes > li {
+ background: #fff;
+ position: relative;
+ list-style: none;
+ display: block;
+ float: left;
+ padding: 0 1em 2em 1em;
+ max-width: 600px;
+ z-index: 1;
+ margin: 12px;
+ -webkit-box-shadow: 0 2px 6px #444;
+ -webkit-border-radius: 6px;
+ -moz-box-shadow: 0 2px 6px #444;
+ -moz-border-radius: 6px;
+ box-shadow: 0 2px 6px #444;
+ border-radius: 6px;
+ }
+ ul.boxes > li:after {
+ content: "\\02192";
+ display: block;
+ position: absolute;
+ top: 0px;
+ right: -16px;
+ font-size: 200%;
+ font-weight: bold;
+ background: #fff;
+ z-index: 5;
+ background: -webkit-gradient(linear, left top, right top, from(#fff), to(#aaa));
+ background: -moz-gradient(linear, left top, right top, from(#fff), to(#aaa));
+ background: gradient(linear, left top, right top, from(#fff), to(#aaa));
+
+ }
+ ul.boxes > li:last-child:after {
+ content: "";
+ }
+ ul.boxes h3 { }
+ .light { font-weight: normal; }
+ ul.boxes li ul { padding-left: 1.5em; }
+ li.warn { color: red; list-style-type: disc; }
+ .todo { font-style: italic; color: #bbb; }
+ .todo:before { content: "(";}
+ .todo:after { content: ")";}
+ .info { color: #222; }
+ .unk, .unk a { color: #aaa; text-decoration: none; }
+ .warning { color: orange; list-style-type: disc; }
+ .error, .failed { color: red; list-style-type: disc; }
+ .ok { color: green; }
+ .isobuild td,
+ .isobuild th { vertical-align: top; }
+ td.build-id { text-align: right; }
+ div.dnotes { color: #666; border: 1px solid #666; padding: 0.6em; font-size: 90%; }
+ div.dnotes:before { content: "Design Notes"; color: #666; font-weight: bold; text-decoration: underline; }
+ </style>
+ </head>
+ <body>
+ <h1>Mageia build chain dashboard</h1>
+ <ul class="boxes">{$ret}</ul>
+
+ <hr>
+ <div class="dnotes">
+ <ul>
+ <li>Light gray values are unknown for now.</li>
+ <li><strong>ISO Build block is still a mockup, doesn't work for now!</strong></li>
+ <li>code is in <a href="http://svnweb.mageia.org/soft/dashboard/">svnweb.mageia.org/soft/dashboard</a>;
+ to get a copy of the code: <pre>$ svn checkout svn://svn.mageia.org/svn/soft/dashboard</pre>
+ patches welcome!</li>
+ </ul>
+ </div>
+ </body>
+ </html>
+S;
+ return $s;
+ }
+} \ No newline at end of file
diff --git a/docs/mageia-dashboard-mockup-201102-rda.html b/docs/mageia-dashboard-mockup-201102-rda.html
new file mode 100644
index 0000000..b8af354
--- /dev/null
+++ b/docs/mageia-dashboard-mockup-201102-rda.html
@@ -0,0 +1,266 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <style>
+ body { font-size: 80%; font-family: Helvetica; background: #aaa; }
+ .clear, hr { clear: both; }
+ ul.boxes { margin: 0; padding: 0; /*width: 1800px;*/ }
+ ul.boxes > li { padding-bottom: 2em; }
+ ul.boxes > li {
+ background: #fff;
+ position: relative;
+ list-style: none;
+ display: block;
+ float: left;
+ padding: 0 1em 2em 1em;
+ max-width: 600px;
+ z-index: 1;
+ margin: 12px;
+ -webkit-box-shadow: 0 2px 6px #444;
+ -webkit-border-radius: 6px;
+ -moz-box-shadow: 0 2px 6px #444;
+ -moz-border-radius: 6px;
+ box-shadow: 0 2px 6px #444;
+ border-radius: 6px;
+ }
+ ul.boxes > li:after {
+ content: "\02192";
+ display: block;
+ position: absolute;
+ top: 0px;
+ right: -16px;
+ font-size: 200%;
+ font-weight: bold;
+ background: #fff;
+ z-index: 5;
+ background: -webkit-gradient(linear, left top, right top, from(#fff), to(#aaa));
+ background: -moz-gradient(linear, left top, right top, from(#fff), to(#aaa));
+ background: gradient(linear, left top, right top, from(#fff), to(#aaa));
+
+ }
+ ul.boxes > li:last-child:after {
+ content: "";
+ }
+ ul.boxes h3 { }
+ .light { font-weight: normal; }
+ ul.boxes li ul { padding-left: 1.5em; }
+ li.warn { color: red; list-style-type: disc; }
+ .todo { font-style: italic; color: #bbb; }
+ .todo:before { content: "(";}
+ .todo:after { content: ")";}
+ .info { color: #222; }
+ .unk, .unk a { color: #aaa; text-decoration: none; }
+ .warning { color: orange; list-style-type: disc; }
+ .error, .failed { color: red; list-style-type: disc; }
+ .ok { color: green; }
+ .isobuild td,
+ .isobuild th { vertical-align: top; }
+ td.build-id { text-align: right; }
+ p#mockup-sign {
+ position: absolute;
+ top: 0; left: -6em;
+ width: 10em;
+ background: red;
+ color: white;
+ border: 2px solid white;
+ padding: 0.3em 0 0.3em 6em;
+ font-weight: bold;
+ text-shadow: -1px 1px 2px #888;
+ -moz-transform: rotate(-45deg);
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ -webkit-box-shadow: 0 1px 6px #888;
+ -moz-box-shadow: 0 1px 6px #888;
+ box-shadow: 0 1px 6px #888;
+ }
+ div.dnotes { color: #666; border: 1px solid #666; padding: 0.6em; font-size: 85%; }
+ div.dnotes:before { content: "Design Notes"; color: #666; font-weight: bold; text-decoration: underline; }
+ </style>
+</head>
+<body>
+ <p id="mockup-sign">Mockup!</p>
+ <h1>Mageia factory status dashboard</h1>
+ <p>This document aggregates various reports from Mageia build chain, from source code to shipped test ISOs.</p>
+ <ul class="boxes">
+ <li><h3>Upstream Projects</h3>
+ <p>Status: <span class="unk">?</span></p>
+ <ul>
+ <li class="unk">32 in mageia/soft, view <a href="">svnweb</a></li>
+ <li class="unk">2343 in other places</li>
+ <li class="unk">143 out of sync with upstream</li>
+ </ul>
+ <p>view <a href="">detailed report</a></p>
+ </li>
+ <li><h3>Source Packages</h3>
+ <p>Status: <span class="unk">?</span></p>
+ <ul>
+ <li class="unk">?GB</li>
+ <li class="unk">? packages</li>
+ <li class="unk">? <a href="">orphans</a></li>
+ <li class="">432 <a href="">out-of-upstream-sync</a></li>
+ <li class="unk">? <a href="">patches</a></li>
+ <li class="unk">? <a href="">open bugs</a> on 43 packages</li>
+ <li class="unk">? <a href="">rpmlint errors</a> in 23 packages (5%)</li>
+ <li class="unk">? <a href="">rpmlint warnings</a> in 3325 packages</li>
+ </ul>
+ <p>view <a href="">svn</a>, <a href="">git</a>,
+ <a href="">detailed report</a></p>
+ </li>
+ <li><h3>Packages Build <span class="light">(past 24 hours)</span></h3>
+ <p>Status: <span class="unk">?</span></p>
+ <ul>
+ <li class="unk">5 nodes working out of 6</li>
+ <li class="unk">used 78% of the time</li>
+ <li class="unk">queue size: <span title="min">0</span>/<span title="max">20</span>/<span title="average">4</span></li>
+ <li class="unk">built time: min/max/avg</li>
+ <li class="unk">wait time: min/max/avg</li>
+ <li class="unk">1234 built packages</li>
+ <li class="unk">321 not built (%):
+ <ul>
+ <li>missing dependencies %</li>
+ <li>other</li>
+ </ul>
+ </li>
+ </ul>
+ <p>view <a href="">pkgsubmit</a>, <a href="">detailed report</a></p>
+ </li>
+ <li><h3>Cauldron Compiled Packages</h3>
+ <p>Status: <span class="unk">?</span></p>
+ <ul>
+ <li class="unk">?GB</li>
+ <li class="unk">? packages</li>
+ <li class="unk">Broken hdlist (i586/nonfree)</li>
+ <li class="unk">Signatures: 23 missing (i586/nonfree, i586/tainted)</li>
+ <li class="unk">Dependencies: 32 missing, 2 circular</li>
+ <li class="unk">15 packages are not in sync with their source</li>
+ <li class="unk">432 missing/broken signatures</li>
+ <li class="unk"><a href="">213 bugs</a></li>
+ <li class="unk">@todo: per package test suite? rpmlint, other</li>
+ <li class="unk">@todo: src => 32/64/arm</li>
+ <li class="unk">Basesystem size: 437MB, w/o suggests: 163MB</li>
+ </ul>
+ <p>view <a href="">repository</a>, <a href="">detailed report</a></p>
+
+ <div class="dnotes">
+ <ul>
+ <li>how to visualize several trees at once? (stable &amp; cauldron at least)</li>
+ </ul>
+ </div>
+ </li>
+ <li><h3>Cauldron ISO Build / QA / Publication <span class="light">(past 3 days)</span></h3>
+ <p>Status: <span class="ok">READY, OK</span></p>
+ <ul>
+ <li><p>Built packages tree is not ready &ndash; no build planned.</p>Or:</li>
+ <li><p>Next build 1a1 should start in about 12 hours (at 2011-03-15-20:23:33),
+ with a <a href="">new context</a>.</p>Or:</li>
+ <li><h4>Build 1a0
+ <span style="font-weight: normal;">(<a href="">context diff w/ build 199</a>)</span>
+ &ndash; 2011-03-14 23:03:15</h4>
+ <ul>
+ <li>DVD i586,
+ <span class="ok">build ok</span> (<a href="">log</a>),
+ <span class="failed">tests failed</span> (<a href="">log</a>),
+ <a href="">cauldron-2-dvd-i586-1a0-qafail.iso</a></li>
+ <li>DVD x86_64,
+ <span class="ok">build ok</span> (<a href="">log</a>),
+ <span class="ok">tests ok</span> (<a href="">log</a>),
+ <a href="">cauldron-2-dvd-i586-1a0-ok.iso</a></li>
+ <li>CD dual,
+ <span class="failed">build failed</span> (<a href="">log</a>)</li>
+ <li>building netinstall image...</li>
+ </ul>
+ <li><h4>Build 199
+ <span style="font-weight: normal;">(<a href="">context diff w/ build 198</a>)</span>
+ &ndash; 2011-03-12 23:03:15</h4>
+ <table border="1" class="isobuild">
+ <tbody>
+ <tr>
+ <th>Item</th>
+ <th>Build</th>
+ <th>Tests</th>
+ <th>Download</th>
+ </tr>
+ <tr>
+ <td>DVD i586</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><a href="">cauldron-2-1a0-dvd-i586-ok.iso</a></td>
+ </tr>
+ <tr>
+ <td>DVD x86_64</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><span class="failed">FAILED</span> (<a href="">log</a>)</td>
+ <td><a href="">cauldron-2-1a0-dvd-x86_64-qafail.iso</a></td>
+ </tr>
+ <tr>
+ <td>CD dual</td>
+ <td><span class="failed">FAILED</span> (<a href="">log</a>)</td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>netinstall</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><span class="ok">OK</span> (<a href="">log</a>)</td>
+ <td><a href="">cauldron-2-1a0-netinstall-ok.iso</td>
+ </tr>
+ </tbody>
+ </table>
+
+ </li>
+ </ul>
+
+ <p><strong>Notes.</strong>
+ Successfully built ISOs are automatically tested (<a href="">view ISO QA docs</a>)
+ and pushed to <a href="">isos.mageia.org/daily</a>.
+ Failed ISOs are kept for review.
+ All ISOs are dropped after 7 days of age.</p>
+ <div class="dnotes">
+ <ul>
+ <li>A "context" is the whole context of an ISO build:
+ packages tree status, particular config status.</li>
+ <li>Not sure about the layout for a build result: list or table?</li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+
+ <hr />
+ <div class="dnotes">
+ <p>Essayer : droite/gauche (renversé), haut/bas (renversé) pour mettre le focus (premier item lu en haut à gauche)
+ soit sur le résultat (les ISOs) soit sur la source.</p>
+ </div>
+
+ <ul class="boxes">
+ <li style="width:300px;"><h3>Search</h3>
+
+ <p>Have a search for packages infos + high-level report matrix.</p>
+
+ <p><input type="search"><input type="submit"></p>
+ </li>
+ <li><h3>indexhtml</h3>
+ <ul>
+ <li>upstream: ... version</li>
+ <li>source size</li>
+ <li>spec file OK</li>
+ <li>maintained by rda, ennael</li>
+ <li>no patch</li>
+ <li>2 bugs</li>
+ <li>2 rpmlint warning</li>
+ <li>License</li>
+ <li>built version ... in 2 minutes (log)</li>
+ <li>last rebuilt on ...</li>
+ <li>Needed by: evolution (needs rebuild), firefox (needs rebuild)</li>
+ <li>RPM: noarch: 230kB</li>
+ <li>in core</li>
+ <li>in hdlist</li>
+ <li>signature OK</li>
+ <li>dependencies OK</li>
+ </ul>
+ </li>
+ </ul>
+ <hr>
+
+</body>
+</html> \ No newline at end of file
diff --git a/make_report.php b/make_report.php
new file mode 100644
index 0000000..be11d18
--- /dev/null
+++ b/make_report.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Generate dashboard static report page.
+ *
+ * Should be called by a cron job, every 15 minutes.
+ *
+ * PHP version 5
+ *
+ * @category Dashboard
+ * @package Buildsystem
+ * @author Romain d'Alverny <rda@mageia.org>
+ * @license MIT License, see LICENSE.txt
+ * @link http://svnweb.mageia.org/svn/soft/dashboard/
+*/
+
+require 'Report/Box.php';
+require 'Report/HTML.php';
+
+Report_Box::run_report();
+die;
+
+// todo locales/languages summary : how many in total, which coverage globally?
+
+$a = new Report_Box_SourcePackage();
+//$a->update();
+print_r($a->render());
+
+echo "\n"; \ No newline at end of file