<?php $INC = isset($INC) ? $INC : dirname(__FILE__); require_once($INC . '/repo.inc.php'); require_once($INC . '/user.inc.php'); /* * Function to load job list */ function rg_builder_load_jobs($db, $where, $order, $limit) { $ret = array(); $ret['ok'] = 0; $ret['list'] = array(); while (1) { $sql = 'SELECT * FROM build_jobs' . ' WHERE ' . $where . ' ORDER BY ' . $order . ' ' . $limit; $res = rg_sql_query($db, $sql); if ($res === FALSE) break; while (($row = rg_sql_fetch_array($res))) { $jid = $row['id']; // TODO: set 'url' when adding the job in queue! // Why not now? // TODO: in case of errors, we should abort the job! $row['request'] = rg_unserialize($row['request']); if ($row['request'] === FALSE) $row['request'] = array(); $row['status'] = rg_unserialize($row['status']); if ($row['status'] === FALSE) $row['status'] = array(); $ret['list'][$jid] = $row; } rg_sql_free_result($res); $ret['ok'] = 1; break; } return $ret; } /* * Add a build job in queue */ function rg_builder_add($db, $repo_id, $d) { rg_log_ml('builder_add: ' . print_r($d, TRUE)); $ret = array('ok' => 0); while (1) { $params = array( 'repo_id' => $repo_id, 'prio' => 10, // TODO 'itime' => time(), 'request' => rg_serialize($d), 'done' => 0, 'status' => '' ); $sql = 'INSERT INTO build_jobs (repo_id, prio, itime' . ', request, done, status)' . ' VALUES (@@repo_id@@, @@prio@@, @@itime@@' . ', @@request@@, @@done@@, @@status@@)'; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { $ret['errmsg'] = 'cannot add job'; break; } rg_sql_free_result($res); // TODO: notify build system to not poll? $ret['ok'] = 1; break; } return $ret; } /* * List virtual machines * TODO: for now, only libvirt */ function rg_builder_vm_list() { $cmd = 'virsh list --name'; $r = rg_exec($cmd, '', FALSE, FALSE, FALSE); if ($r['ok'] != 1) { rg_log('Cannot find out virtual machines: ' . $r['errmsg']); return FALSE; } return explode("\n", trim($r['data'])); } /* * Function executed when a job is done */ function rg_builder_done($db, $job, $s) { rg_log_enter('builder_done'); //rg_log_ml('DEBUG: builder_done: job: ' . print_r($job, TRUE)); //rg_log_ml('DEBUG: builder_done: status: ' . print_r($s, TRUE)); // old way $req = isset($job['request']) ? $job['request'] : $job; $job['done'] = time(); $ret = FALSE; $rollback = FALSE; while (1) { $res = rg_sql_begin($db); if ($res === FALSE) break; $rollback = TRUE; $labels = $s['labels']; // Some cosmetic stuff $env = $req['env']; $labels[] = 'worker_elap/' . ($s['done'] - $s['start']) . 's'; $labels[] = 'wait_time/' . ($job['worker_sent'] - $job['itime']) . 's'; $labels[] = 'date/' . gmdate('Y-m-d', $job['itime']); $labels[] = 'time/' . gmdate('H:i', $job['itime']); // add labels to the commit $params = array( 'repo_id' => $job['repo_id'], 'head' => $req['head'], 'type' => 'build', 'misc' => $env, 'labels' => rg_serialize($labels), 'itime' => time() ); $sql = 'DELETE FROM commit_labels' . ' WHERE repo_id = @@repo_id@@' . ' AND type = @@type@@' . ' AND misc = @@misc@@' . ' AND head = @@head@@'; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) break; rg_sql_free_result($res); $sql = 'INSERT INTO commit_labels (repo_id, head, type, misc' . ', labels, itime)' . ' VALUES (@@repo_id@@, @@head@@, @@type@@' . ', @@misc@@, @@labels@@, @@itime@@)'; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) break; rg_sql_free_result($res); rg_cache_unset('repo_commit_labels' . '::' . $job['repo_id'] . '::' . $req['head'], RG_SOCKET_NO_WAIT); $params = array( 'id' => $job['id'], 'done' => $job['done'], 'status' => rg_serialize($s) ); $sql = 'UPDATE build_jobs SET done = @@done@@' . ', status = @@status@@' . ' WHERE id = @@id@@'; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) break; rg_sql_free_result($res); $ev = array( 'category' => 'wh_build_job_done', 'prio' => 100, 'ui' => array('uid' => $req['uid']), 'job' => $job, 'status' => $s ); $r = rg_event_add($db, $ev); if ($r !== TRUE) { rg_repo_set_error('cannot add event' . ' (' . rg_event_error() . ')'); break; } $res = rg_sql_commit($db); if ($res === FALSE) break; $rollback = FALSE; $key = 'wh' . '::' . $req['uid'] . '::' . 'list' . '::' . $req['hook_id']; unset($params['id']); rg_cache_merge($key, $params, RG_SOCKET_NO_WAIT); rg_event_signal_daemon('', 0); $ret = TRUE; break; } if ($rollback) rg_sql_rollback($db); rg_log_exit(); return $ret; } /* * Nice status for a job */ function rg_builder_nice_status(&$a) { rg_log_ml('DEBUG: nice_status: a: ' . print_r($a, TRUE)); $a['start_nice'] = gmdate('Y-m-d H:i', intval($a['start'])); $a['net_ok_nice'] = gmdate('Y-m-d H:i', intval($a['net_ok'])); $a['pkgs_ok_nice'] = gmdate('Y-m-d H:i', intval($a['pkgs_ok'])); $a['done_nice'] = gmdate('Y-m-d H:i', intval($a['done'])); if (isset($a['vm_start']) && ($a['vm_start'] > 0)) $a['vm_start_nice'] = gmdate('Y-m-d H:i', $a['vm_start']); else $a['vm_start_nice'] = 'n/a'; if (isset($a['build_sh_start']) && ($a['build_sh_start'] > 0)) $a['build_sh_start_nice'] = gmdate('Y-m-d H:i', trim($a['build_sh_start'])); else $a['build_sh_start_nice'] = 'n/a'; if (!isset($a['clone_elap'])) $a['clone_elap_nice'] = 'n/a'; else $a['clone_elap_nice'] = $a['clone_elap'] . 's'; foreach ($a['cmds'] as &$i) { if (empty($i['start'])) continue; $i['start_nice'] = gmdate('Y-m-d H:i', intval($i['start'])); $i['done_nice'] = gmdate('Y-m-d H:i', intval($i['done'])); $i['elap'] = rg_human_time_interval($i['done'] - $i['start'] + 1); $_a = rg_xss_safe($i['log']); $i['HTML:log_nlbr'] = nl2br($_a); } } /* * Cosmetic fixes */ function rg_builder_cosmetic($db, &$row) { rg_log_ml('DEBUG: builder_cosmetic: ' . print_r($row, TRUE)); if (isset($row['itime'])) $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']); else $row['itime_nice'] = 'n/a'; if (!isset($row['done'])) $row['done'] = 0; if ($row['done'] > 0) $row['done_nice'] = gmdate('Y-m-d H:i', $row['done']); else $row['done_nice'] = 'n/a'; $ri = rg_repo_info($db, $row['repo_id'], 0, ''); if ($ri['ok'] == 1) { $row['ri'] = $ri; $row['user'] = rg_user_nice($db, $row['ri']['uid']); } else { $row['ri'] = array('name' => 'n/a'); $row['user'] = 'n/a'; } } /* * Lists the build jobs */ function rg_builder_list_high_level($db, $rg, $op, $paras) { rg_prof_start('builder_list_high_level'); rg_log_enter('builder_list_high_level op=' . $op); $ret = ''; $errmsg = array(); $rg['HTML:status'] = ''; if ($rg['login_ui']['is_admin'] == 1) $where = '1 = 1'; else $where = 'repo_id IN (SELECT repo_id FROM repos' . ' WHERE uid = ' . $rg['login_ui']['uid'] . ')'; if (strcmp($op, 'queue') == 0) $where .= ' AND done = 0'; $r = rg_builder_load_jobs($db, $where, 'itime DESC', 'LIMIT 100'); if ($r['ok'] != 1) return rg_template('builder/load_err.html', $rg, TRUE /*xss*/); // Preparing the list for template $d = array(); foreach ($r['list'] as $_id => &$i) { rg_builder_cosmetic($db, $i); if (empty($i['status'])) { $i['HTML:status_list'] = 'n/a'; } else { if (!empty($i['status']['packages'])) { $_x = array(); $_x['packages'] = rg_xss_safe($i['status']['packages']); $i['HTML:status_packages'] = rg_template('builder/packages.html', $_x, TRUE/*xss*/); } else { $i['HTML:status_packages'] = ''; } rg_builder_nice_status($i['status']); $i['HTML:status_list'] = rg_template_table('builder/cmds', $i['status']['cmds'], $rg); } $d[] = $i; } rg_log_ml('DEBUG: d: ' . print_r($d, TRUE)); return rg_template_table('builder/queue', $d, $rg); }