summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbackend/backend.php6
-rw-r--r--backend/functions/build.php2
-rw-r--r--backend/functions/execution.php12
-rw-r--r--backend/functions/log.php2
-rw-r--r--frontend/index.php6
-rw-r--r--frontend/pages/wizard.php83
l---------frontend/pages/wizard/step0.php1
-rw-r--r--frontend/pages/wizard/step1.php11
-rw-r--r--shared/classes/0sql_row_obj.php1
-rw-r--r--shared/classes/build.php43
-rw-r--r--shared/classes/buildlog_entry.php2
-rw-r--r--shared/classes/buildopt.php3
-rw-r--r--shared/classes/session.php3
-rw-r--r--shared/classes/task.php25
-rw-r--r--todo10
15 files changed, 169 insertions, 41 deletions
diff --git a/backend/backend.php b/backend/backend.php
index 1cb1cdb..0dbd8a9 100755
--- a/backend/backend.php
+++ b/backend/backend.php
@@ -19,15 +19,19 @@ if (isset($opts['f'])) {
}
while (true) {
// TODO check first for builds that need to be resumed
- $r=$pdo->query('SELECT * FROM `builds` WHERE `status`="build/ready" LIMIT 1'); // TODO ORDER BY `ctime` ASC
+ $r=$pdo->query('SELECT * FROM `builds` WHERE `status`="build/ready" ORDER BY `ctime` ASC LIMIT 1');
if ($r->rowCount()) {
$build=new sql_build($r->fetch(PDO::FETCH_ASSOC));
+ $build->start=time();
+ $build->write();
echo 'Starting build id='.$build->id."\n";
try {
build($build);
} catch (Exception $e) {
echo 'Caught exception: '.$e->getMessage()."\n";
}
+ $build->finish=time();
+ $build->write();
echo 'Finished with build id='.$build->id."\n";
}
echo 'Sleeping...';
diff --git a/backend/functions/build.php b/backend/functions/build.php
index 3346218..84b2a77 100644
--- a/backend/functions/build.php
+++ b/backend/functions/build.php
@@ -32,7 +32,7 @@ function build(&$build) {
$contents.=strtoupper($name).'="'.$val.'"'."\n";
}
unset($makeconf);
- fatal(log_status('Writing '.$C.'/make.conf:'."\n".indent($contents), file_put_contents($C.'/etc/make.conf', $contents)));
+ fatal(log_status('Writing '.$C.'/make.conf', file_put_contents($C.'/etc/make.conf', $contents)));
unset($contents);
fatal(log_status('Making make.profile symlink to '.$conf['portdir'].'/profiles/'.$headers['profile'], symlink($conf['portdir'].'/profiles/'.$headers['profile'], $C.'/etc/make.profile')));
$env=array(
diff --git a/backend/functions/execution.php b/backend/functions/execution.php
index c201adf..73cef31 100644
--- a/backend/functions/execution.php
+++ b/backend/functions/execution.php
@@ -1,11 +1,14 @@
<?php
+// TODO this should be part of the task class
function log_command(&$build, $command, $path=null, $env=null) {
+ log_msg("Executing $command... ", false);
$descriptorspec=array(
0 => array('pipe', 'r'), // STDIN
1 => array('pipe', 'w'), // STDOUT
2 => array('pipe', 'w') // STDERR
);
$task=new sql_task(null, $build->id, $command, null);
+ $task->start=time();
$task->write();
$p=proc_open($command, $descriptorspec, $pipes, $path, $env);
foreach ($pipes as $pipe) {
@@ -20,19 +23,16 @@ function log_command(&$build, $command, $path=null, $env=null) {
$s=stream_select($outs, $null, $null, 1);
if ($s) {
$c=stream_get_contents($pipes[2]);
- // TODO this really needs to go to the DB and carry metadata
if ($c) {
// STDERR
$entry=new sql_buildlog_entry($task->id, $msg++, time(), 'stderr', $c);
$entry->write();
- //log_msg($c, false);
}
$c=stream_get_contents($pipes[1]);
if ($c) {
// STDOUT
$entry=new sql_buildlog_entry($task->id, $msg++, time(), 'stdout', $c);
$entry->write();
- //log_msg($c, false);
}
}
if ($status['running'] === false) {
@@ -40,6 +40,7 @@ function log_command(&$build, $command, $path=null, $env=null) {
break;
}
}
+ $task->finish=time();
foreach ($pipes as $pipe) {
fclose($pipe);
}
@@ -48,6 +49,11 @@ function log_command(&$build, $command, $path=null, $env=null) {
}
$task->exit=$exit_status;
$task->write();
+ if ($exit_status == 0) {
+ log_msg(color('[success]', 'green'));
+ } else {
+ log_msg(color('[exit code '.$exit_status.']', 'red'));
+ }
// Handle end status
return $exit_status;
}
diff --git a/backend/functions/log.php b/backend/functions/log.php
index c07fd73..1a40a43 100644
--- a/backend/functions/log.php
+++ b/backend/functions/log.php
@@ -17,6 +17,6 @@ function color($msg, $color) {
}
}
function indent($msg, $tabs=1) {
- return str_replace("\n", "\n".str_repeat("\t", $tabs), $msg);
+ return str_repeat("\t", $tabs).str_replace("\n", "\n".str_repeat("\t", $tabs), trim($msg));
}
?>
diff --git a/frontend/index.php b/frontend/index.php
index 0677c58..b66257a 100644
--- a/frontend/index.php
+++ b/frontend/index.php
@@ -63,8 +63,10 @@ for ($line=fgets($routing, 32768); !feof($routing); $line=fgets($routing, 32768)
$dest=$value;
}
} else {
- require_once('include/header.php');
- die(print_error('Routing Failure', 'Init function undefined for '.$dest.'.'));
+ debug('routing','No init function for '.$dest.'... continuing to body');
+ break;
+// require_once('include/header.php');
+// die(print_error('Routing Failure', 'Init function undefined for '.$dest.'.'));
}
}
if (!$S['notemplates']) {
diff --git a/frontend/pages/wizard.php b/frontend/pages/wizard.php
index dee3c57..e9af804 100644
--- a/frontend/pages/wizard.php
+++ b/frontend/pages/wizard.php
@@ -1,32 +1,79 @@
<?php
function init_wizard() {
global $S, $request;
- // TODO we shouldn't have to set the step this way, it should be stored in SQL
- if (isset($S['user'])) {
- if (isset($request['finished'])) {
- return 'wizard/end';
- } elseif (isset($request['step']) && is_array($request['step']) && count($request['step']) == 1) {
- $keys=array_keys($request['step']);
- if (is_numeric($keys[0]) && is_file(FRONTEND.'/pages/wizard/step'.$keys[0].'.php')) {
- return 'wizard/step'.$keys[0];
+ if (!isset($S['user'])) {
+ return 'login';
+ }
+ if (isset($request['step']) && is_array($request['step']) && count($request['step']) == 1) {
+ $keys=array_keys($request['step']);
+ if (is_numeric($keys[0]) && is_file(FRONTEND.'/pages/wizard/step'.$keys[0].'.php')) {
+ $step=$keys[0];
+ $r=$S['pdo']->query('SELECT * FROM `builds` WHERE `owner`='.$S['user']->id.' AND `status`="config/step'.$step.'"');
+ if ($r->rowCount() == 0) {
+ debug('wizard', 'Build not found!');
+ // Build
+ unset($request['step']);
+ return 'wizard';
+ }
+ $S['build']=new sql_build($r->fetch(PDO::FETCH_ASSOC));
+ require_once(FRONTEND.'/pages/wizard/step'.$step.'.php');
+ $proc='process_wizard_step'.$step;
+ if (function_exists($proc)) {
+ $proc();
} else {
- debug('Not numeric, or file not existant for '.$keys[0]);
+ debug('wizard', 'No processing function for step '.$step);
}
+ $step++;
+ if (is_file(FRONTEND.'/pages/wizard/step'.$step.'.php')) {
+ $S['build']->status='config/step'.$step;
+ $S['build']->write();
+ $S['title']='Create - Step '.$step;
+ return 'wizard/step'.$step;
+ } else {
+ $S['build']->status='build/ready';
+ $S['build']->ctime=time();
+ $S['build']->write();
+ return array('title' => 'Create - Finished');
+ }
+ } else {
+ debug('wizard', 'step[0] not numeric, or step '.htmlentities($step).' not existant');
}
- return array('title' => 'Create');
} else {
- return 'login';
+ $r=$S['pdo']->query('SELECT * FROM `builds` WHERE `owner`='.$S['user']->id.' AND `status` LIKE "config/step0"');
+ if ($r->rowCount()) {
+ $S['build']=new sql_build($r->fetch(PDO::FETCH_ASSOC));
+ } else {
+ $S['build']=new sql_build();
+ $S['build']->init();
+ }
}
+ return array('title' => 'Create');
}
function body_wizard() {
global $S;
- echo '<form action="'.url('create').'" method="post"><h3>Request an image built</h3>Name of your build (optional): <input name="name" /><br/>Profile: <select name="pkgdir">';
- $r=$S['pdo']->query('SELECT * FROM `profiles` WHERE `flags` NOT LIKE "%d%"'); // d for disabled
- while ($profile=$r->fetch(PDO::FETCH_ASSOC)) {
- $profile=new sql_profile($profile);
- $display=$profile->name?$profile->name:($profile->pkgdir?$profile->pkgdir:'/');
- echo '<option value="'.htmlentities($profile->pkgdir).'">'.htmlentities($display).'</option>';
+ if ($S['build']->status == 'config/step0') {
+ echo '<form action="'.url('create').'" method="post"><h3>Request an image built</h3>Name of your build (optional): <input name="name" /><br/>Profile: <select name="pkgdir">';
+ $r=$S['pdo']->query('SELECT * FROM `profiles` WHERE `flags` NOT LIKE "%d%"'); // d for disabled
+ while ($profile=$r->fetch(PDO::FETCH_ASSOC)) {
+ $profile=new sql_profile($profile);
+ $display=$profile->name?$profile->name:($profile->pkgdir?$profile->pkgdir:'/');
+ echo '<option value="'.htmlentities($profile->pkgdir).'">'.htmlentities($display).'</option>';
+ }
+ echo '</select><br/><input type="submit" name="step[0]" value="Start" /></form>';
+ } else {
+ echo '<h3>Config finished!</h3><p>Check your build\'s status <a href="'.url('logs/build'.$S['build']->id).'">here</a></p>';
}
- echo '</select><br/><input type="submit" name="step[1]" value="Start" /></form>';
+}
+function process_wizard_step0() {
+ global $S, $request;
+ $S['build']->name=$request['name'];
+ $profile=new sql_profile($request['pkgdir']);
+ $profileopt=new sql_buildopt($S['build']->id, 'profile', $profile->pkgdir); // TODO pkgdir -> id
+ $profileopt->write();
+ $S['build']->write();
+}
+// One day this is going to be necessary
+function body_wizard_step0() {
+ body_wizard();
}
?>
diff --git a/frontend/pages/wizard/step0.php b/frontend/pages/wizard/step0.php
new file mode 120000
index 0000000..cfe4a1c
--- /dev/null
+++ b/frontend/pages/wizard/step0.php
@@ -0,0 +1 @@
+../wizard.php \ No newline at end of file
diff --git a/frontend/pages/wizard/step1.php b/frontend/pages/wizard/step1.php
new file mode 100644
index 0000000..baef871
--- /dev/null
+++ b/frontend/pages/wizard/step1.php
@@ -0,0 +1,11 @@
+<?php
+function init_wizard_step1() {
+ return array('title' => 'Create - Step 1');
+}
+function body_wizard_step1() {
+ global $S;
+ $build=&$S['build'];
+ $opts=$build->get_buildopts();
+ echo '<h3>Step 1</h3><form action="'.url('create').'" method="post"><input type="submit" name="step[1]" value="Build!" /></form>';
+}
+?>
diff --git a/shared/classes/0sql_row_obj.php b/shared/classes/0sql_row_obj.php
index cf82e4b..0d75d37 100644
--- a/shared/classes/0sql_row_obj.php
+++ b/shared/classes/0sql_row_obj.php
@@ -1,5 +1,6 @@
<?php
// TODO
+// Fall back to multi key if single key didn't work (so unique key can be null)
// consider replacing the one sql_col class with a bunch of child classes for different types (will work well with defaults() when 5.3.0 comes out)
// make sure things really work with enum
// replace the functionality of hasattrs and getattr somehow - more complex custom queries than refers_to
diff --git a/shared/classes/build.php b/shared/classes/build.php
index 305dd8e..6034cf5 100644
--- a/shared/classes/build.php
+++ b/shared/classes/build.php
@@ -1,17 +1,17 @@
<?php
class sql_build extends sql_row_obj {
- protected $table='builds', $columns=array(
+ protected $table='builds', $ids='id owner', $columns=array(
'id' => array (
'type' => 'CHAR',
'length' => 6,
'not_null' => true,
- 'unique' => true
),
'owner' => array (
'type' => 'INT',
'length' => 10,
'unsigned' => true,
- 'not_null' => true
+ 'not_null' => true,
+ 'refers to' => 'users.id'
),
'name' => array (
'type' => 'VARCHAR',
@@ -22,6 +22,11 @@ class sql_build extends sql_row_obj {
'length' => 255,
'not_null' => true
),
+ 'ctime' => array (
+ 'type' => 'INT',
+ 'length' => 10,
+ 'unsigned' => true
+ ),
'start' => array (
'type' => 'INT',
'length' => 10,
@@ -32,7 +37,37 @@ class sql_build extends sql_row_obj {
'length' => 10,
'unsigned' => true
)
-
);
+ // Generates a unique id and sets status to config/step0, writes self to db and returns id
+ public function init() {
+ global $S;
+ $this->owner=$S['user']->id;
+ $this->status='config/step0';
+ $fails=0;
+ while (true) {
+ $id=randstring(6);
+ debug("Trying id=$id...");
+ $r=$S['pdo']->query('SELECT `id` FROM `builds` WHERE `id`="'.$id.'"');
+ if ($r->rowCount() == 0) {
+ break;
+ }
+ if (++$fails == 10) {
+ throw new Exception('Failed 10 times to find a unique build id... this shouldn\'t happen.');
+ }
+ }
+ $this->id=$id;
+ $this->write();
+ return $this->id;
+ }
+ // Fetches all available buildopts pertaining to this build in a nice array
+ function get_buildopts() {
+ global $S;
+ $r=$S['pdo']->query('SELECT * FROM `buildopts` WHERE `build`="'.$this->id.'"');
+ $opts=array();
+ while ($opt=$r->fetch(PDO::FETCH_ASSOC)) {
+ $opt=new sql_buildopt($opt);
+ $opts=&$opt;
+ }
+ }
}
?>
diff --git a/shared/classes/buildlog_entry.php b/shared/classes/buildlog_entry.php
index f060e9e..69d689f 100644
--- a/shared/classes/buildlog_entry.php
+++ b/shared/classes/buildlog_entry.php
@@ -6,7 +6,7 @@ class sql_buildlog_entry extends sql_row_obj {
'length' => 10,
'unsigned' => true,
'not_null' => true,
- 'default' => 0
+ 'refers to' => 'tasks.id'
),
'order' => array (
'type' => 'INT',
diff --git a/shared/classes/buildopt.php b/shared/classes/buildopt.php
index e05192b..4999585 100644
--- a/shared/classes/buildopt.php
+++ b/shared/classes/buildopt.php
@@ -4,7 +4,8 @@ class sql_buildopt extends sql_row_obj {
'build' => array (
'type' => 'CHAR',
'length' => 6,
- 'not_null' => true
+ 'not_null' => true,
+ 'refers to' => 'builds.id'
),
'name' => array (
'type' => 'VARCHAR',
diff --git a/shared/classes/session.php b/shared/classes/session.php
index 9b8a0a2..2cab1cb 100644
--- a/shared/classes/session.php
+++ b/shared/classes/session.php
@@ -10,7 +10,8 @@ class sql_session extends sql_row_obj {
'type' => 'INT',
'length' => 10,
'unsigned' => true,
- 'not_null' => true
+ 'not_null' => true,
+ 'refers to' => 'users.id'
),
'atime' => array (
'type' => 'INT',
diff --git a/shared/classes/task.php b/shared/classes/task.php
index 3eecdeb..cdea343 100644
--- a/shared/classes/task.php
+++ b/shared/classes/task.php
@@ -5,23 +5,36 @@ class sql_task extends sql_row_obj {
'type' => 'INT',
'length' => 10,
'unsigned' => true,
- 'not null' => true,
- 'auto increment' => true,
+ 'not_null' => true,
+ 'auto_increment' => true
),
- 'build' => array(
+ 'build' => array (
'type' => 'CHAR',
'length' => 6,
- 'not null' => true,
+ 'not_null' => true,
+ 'default' => ''
),
'command' => array (
'type' => 'VARCHAR',
'length' => 255,
- 'not null' => true,
+ 'not_null' => true,
+ 'default' => ''
+ ),
+ 'start' => array (
+ 'type' => 'INT',
+ 'length' => 10,
+ 'unsigned' => true,
+ 'not_null' => true
+ ),
+ 'end' => array (
+ 'type' => 'INT',
+ 'length' => 10,
+ 'unsigned' => true
),
'exit' => array (
'type' => 'TINYINT',
'length' => 3,
- 'unsigned' => true,
+ 'unsigned' => true
)
);
diff --git a/todo b/todo
index f032b6e..01d1423 100644
--- a/todo
+++ b/todo
@@ -4,6 +4,12 @@ Investigate using testing branch of portage (2.2)
Add a builds table and class, integrate it in backend
Add signal handling to the backend so when you hit Ctrl-C, it doesn't leave the logs saying "running" for the current task
Find kernels
-Add a 'ctime' column to builds so we know which ones to start first
-Add status column of builds to log viewer
+Add status column of builds to log viewer (and ctime, start, finish)
Post first weekly report to gentoo-dev, gentoo-soc
+Move more functions into corresponding classes
+Give profiles an auto_increment ID so they can have their directories moved without breaking the db
+Have backend handle builds that it finds to already be running
+Add a PID file so backend can't start twice
+Add pagination to log viewer
+Move over extra packages selection from mock-up
+Implement extra packages in backend