L2E6EVE2RVFVDCUNRJ4CZYSQNS2DZUA5DTBETHBDUQUV2KQQRAOQC
TULPZ62YXEHXUWGBZMLCLYILEXPQS5ADPT22574BIRFU4CZMBSKAC
J5UVLXOK6EDIL5I7VKWH4V2QDS4DPD7FHRK6XBWSXFRQS4JKXFZQC
BVOPAMLSAU4UTV3DUX53OYDMXP2SETAQVUKAYE2OTCVVN4RD7LLQC
67P45PY4GTWQXZRCMR734D5YYN2OERZM57NBB2CZXEULQT2GRFNAC
M552HLIAP52D42AVXVC5SGROAYN2TBCEUZOXESWEMBBUX7G3U6TAC
ELCI5T2ALF37VXYM5POHPO3CAMMPRB65BXGDRVUAZG53NKKLGIEAC
WYN733STK5DUQSWHSS6EYZK32KPZII64HLX4NS7TYUSFZ6AAFLGAC
7LKUAIGCURNGNBBOAGK4EYIUF6KNWHJNLA6ZJEXFLA5HUADAJP6QC
K5BEBWKMPMTXDZTZECMJ32LCL354WMOM3RPEFWGHJFB3QH7FH6WAC
UVMFS73TI6RARMAAGY2UVS5LCPZUKLQECXQQVER4F7S4BNUXQQ3AC
7YBYT2LQML2PKEO6UO4444AGSASS664UCDXW2YO3ALB7THQHCEBQC
PHX2HIVGHHKCAX6VNN2WXD4LRGSA74KQMJCCTMHK7HS6JPELVECAC
ZEHSSVFGKP2DCW2MKXHKW3LVHQ3DBCI6JJ36X6YOPLL7SJBXCMPAC
VCOSLZRPLRS3ITD2JIPKZPMTCEPHN4WEFKTE5TKH3RAZ7WJKMQ4AC
X27GNHDV5KPZ5GSH6DCAJMNCEMZLCP7M43JWF2X3O5QWXMOX273AC
IMY5UQE3I2UJRKEFJSW5OM4IY5QGQICDSAKCP7MGWGS7FO4ELXTQC
N22GPKYTOLZLBGTGDATQDVZ4R5APZEAOIA7L32X4UXBH4XNI7MWAC
GWCV3TQVFLUPBREUFRJV6ACJGQHD24NIUAVQQFURMXT3GL2SPPZAC
DVNWJXWWZAR4LGE3FGGY64EW5U6GWH6MXXAALWPO3EMI4NO42ZXAC
FDE3BJAPDEP3BYT5A5GEGLNXPPZLA2KTGXB4ZNYRP4LJ7IFRKYXAC
$c->stash->{allBuilds} = [$c->model('DB::Builds')->search(undef, {order_by => "timestamp DESC"})];
# Get the latest build for each unique job.
# select * from builds as x where timestamp == (select max(timestamp) from builds where jobName == x.jobName);
$c->stash->{latestBuilds} = [$c->model('DB::Builds')->search(undef, {order_by => "project, attrName", where => "timestamp == (select max(timestamp) from builds where project == me.project and attrName == me.attrName)"})];
$c->stash->{scheduled} = [$c->model('DB::Builds')->search(
{finished => 0}, {join => 'schedulingInfo'})]; # !!!
$c->stash->{allBuilds} = [$c->model('DB::Builds')->search(
{finished => 1}, {order_by => "timestamp DESC"})];
# Get the latest finished build for each unique job.
$c->stash->{latestBuilds} = [$c->model('DB::Builds')->search(undef,
{ join => 'resultInfo'
, where => "finished != 0 and timestamp = (select max(timestamp) from Builds where project == me.project and attrName == me.attrName)"
, order_by => "project, attrname"
})];
$c->stash->{builds} = [$c->model('DB::Builds')->search({project => $project, attrName => $jobName}, {order_by => "timestamp DESC"})];
$c->stash->{builds} = [$c->model('DB::Builds')->search(
{finished => 1, project => $project, attrName => $jobName},
{order_by => "timestamp DESC"})];
package HydraFrontend::Schema::Jobs;
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components("Core");
__PACKAGE__->table("jobs");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_nullable => 0, size => undef },
"timestamp",
{ data_type => "integer", is_nullable => 0, size => undef },
"priority",
{ data_type => "integer", is_nullable => 0, size => undef },
"project",
{ data_type => "text", is_nullable => 0, size => undef },
"jobset",
{ data_type => "text", is_nullable => 0, size => undef },
"attrname",
{ data_type => "text", is_nullable => 0, size => undef },
"description",
{ data_type => "text", is_nullable => 0, size => undef },
"drvpath",
{ data_type => "text", is_nullable => 0, size => undef },
"outpath",
{ data_type => "text", is_nullable => 0, size => undef },
"system",
{ data_type => "text", is_nullable => 0, size => undef },
);
__PACKAGE__->set_primary_key("id");
1;
__PACKAGE__->has_many(
"inputs",
"HydraFrontend::Schema::Inputs",
{ "foreign.job" => "self.id" },
);
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZF8UB1MtbPuOk7wTSFJR5Q
__PACKAGE__->belongs_to(
"project",
"HydraFrontend::Schema::Projects",
{ name => "project" },
);
__PACKAGE__->belongs_to(
"jobset",
"HydraFrontend::Schema::Jobsets",
{ name => "jobset", project => "project" },
);
"locker",
{ data_type => "text", is_nullable => 0, size => undef },
{ data_type => "integer", is_nullable => 0, size => undef },
"busy",
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:A3Is4VTFkTl2DzrYjzdrZA
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dKMSSomUN+gJX57Z5e295w
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:eMNna7u2l0ec+OYuvtGRpg
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZOxJeT+ltgyc/zuDl9aEDQ
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LaXQ4zxxvzdKFBRVcjMdMQ
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:rZPTilX/PAiIoxffxc0nJw
package HydraFrontend::Schema::Buildresultinfo;
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components("Core");
__PACKAGE__->table("BuildResultInfo");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_nullable => 0, size => undef },
"iscachedbuild",
{ data_type => "integer", is_nullable => 0, size => undef },
"buildstatus",
{ data_type => "integer", is_nullable => 0, size => undef },
"errormsg",
{ data_type => "text", is_nullable => 0, size => undef },
"starttime",
{ data_type => "integer", is_nullable => 0, size => undef },
"stoptime",
{ data_type => "integer", is_nullable => 0, size => undef },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to("id", "HydraFrontend::Schema::Builds", { id => "id" });
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2Vfqs9RUhbDrje18yZb3AA
# You can replace this text with custom content, and it will be preserved on regeneration
1;
{ data_type => "text", is_nullable => 0, size => undef },
"iscachedbuild",
{ data_type => "integer", is_nullable => 0, size => undef },
"buildstatus",
{ data_type => "integer", is_nullable => 0, size => undef },
"errormsg",
"inputs",
"HydraFrontend::Schema::Inputs",
"buildschedulinginfoes",
"HydraFrontend::Schema::Buildschedulinginfo",
{ "foreign.id" => "self.id" },
);
__PACKAGE__->has_many(
"buildresultinfoes",
"HydraFrontend::Schema::Buildresultinfo",
{ "foreign.id" => "self.id" },
);
__PACKAGE__->has_many(
"buildinputs_builds",
"HydraFrontend::Schema::Buildinputs",
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:C1XPkCXQImyXduKER0Dllg
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1GZeB3YVr064AZrGargmFg
__PACKAGE__->has_many(dependents => 'HydraFrontend::Schema::Buildinputs', 'dependency');
package HydraFrontend::Schema::Buildschedulinginfo;
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components("Core");
__PACKAGE__->table("BuildSchedulingInfo");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_nullable => 0, size => undef },
"priority",
{ data_type => "integer", is_nullable => 0, size => undef },
"busy",
{ data_type => "integer", is_nullable => 0, size => undef },
"locker",
{ data_type => "text", is_nullable => 0, size => undef },
"logfile",
{ data_type => "text", is_nullable => 0, size => undef },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to("id", "HydraFrontend::Schema::Builds", { id => "id" });
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:rN7v2+MnC8TkrEHUzt2Gqg
# You can replace this text with custom content, and it will be preserved on regeneration
1;
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ibTncC1AslPWt1eiTtwplA
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:bvEulSFMDlAMs39sIyHgZQ
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:D1UzSZwPtwDmOI7q6g8uKQ
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:54xK3D1D0Jm5oKgRelXN7Q
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:6Pyrgervmq03S5Nx8QfA1Q
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:JHirlq7Jc8dQOy+Op/VflA
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:p8LbF31qRl/JfMK5wfkeCg
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:7Ag5ZfYVgfw3MJZkNUmBYw
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-10 14:25:07
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dBO/r6lVlITiJ/HlltKcpQ
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1AgCf4sf5h2RU24Slo0sTA
<th>Time added:</th>
<td>[% date.format(build.timestamp, '%Y-%m-%d %H:%M:%S') %]</td>
<th>System:</th>
<td><tt>[% build.system %]</tt></td>
</tr>
<tr>
<th>Derivation store path:</th>
<td><tt>[% build.drvpath %]</tt></td>
</tr>
<tr>
<th>Output store path:</th>
<td><tt>[% build.outpath %]</tt></td>
<td>[% IF build.starttime %][% date.format(build.starttime, '%Y-%m-%d %H:%M:%S') %][% ELSE %]<em>(cached build)</em>[% END %]</td>
<td>[% IF build.resultInfo.starttime %][% date.format(build.resultInfo.starttime, '%Y-%m-%d %H:%M:%S') %][% ELSE %]<em>(cached build)</em>[% END %]</td>
<td>[% IF build.stoptime %][% date.format(build.stoptime, '%Y-%m-%d %H:%M:%S') %][% ELSE %]<em>(cached build)</em>[% END %]</td>
<td>[% IF build.resultInfo.stoptime %][% date.format(build.resultInfo.stoptime, '%Y-%m-%d %H:%M:%S') %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr>
<tr>
<th>Derivation store path:</th>
<td><tt>[% build.drvpath %]</tt></td>
</tr>
<tr>
<th>Output store path:</th>
<td><tt>[% build.outpath %]</tt></td>
</tr>
<tr>
<th>System:</th>
<td><tt>[% build.system %]</tt></td>
[% END %]
[% FOREACH job IN jobs -%]
<tr [% IF job.busy %]class="runningJob"[% END %] >
<td>[% job.id %]</td>
<td>[% job.priority %]</td>
<td><tt>[% job.project.name %]</tt></td>
<td><tt>[% job.jobset.name %]</tt></td>
<td><tt>[% job.system %]</tt></td>
<td>[% date.format(job.timestamp, '%Y-%m-%d %H:%M:%S') %]</td>
<td>[% job.description %]</td>
[% FOREACH build IN scheduled -%]
<tr [% IF build.schedulingInfo.busy %]class="runningJob"[% END %] >
<td><a href="[% c.uri_for('/build' build.id) %]">[% build.id %]</a></td>
<td>[% build.schedulingInfo.priority %]</td>
<td><tt>[% build.project.name %]</tt></td>
<td><tt>[% build.jobset.name %]</tt></td>
<td><tt>[% build.system %]</tt></td>
<td>[% date.format(build.timestamp, '%Y-%m-%d %H:%M:%S') %]</td>
<td>[% build.description %]</td>
my $build = $db->resultset('Builds')->create(
{ timestamp => time()
, project => $job->project->name
, jobset => $job->jobset->name
, attrname => $job->attrname
, description => $job->description
, drvpath => $drvPath
, outpath => $outPath
$build->finished(1);
$build->timestamp(time());
$build->update;
$db->resultset('Buildresultinfo')->create(
{ id => $build->id
# Lock the job. If necessary, steal the lock from the parent process
# (runner.pl). This is so that if the runner dies, the children
# (i.e. the job builders) can continue to run and won't have the lock
# taken away.
my $job;
# Lock the build. If necessary, steal the lock from the parent
# process (runner.pl). This is so that if the runner dies, the
# children (i.e. the build.pl instances) can continue to run and won't
# have the lock taken away.
my $build;
($job) = $db->resultset('Jobs')->search({ id => $jobId });
die "job $jobId doesn't exist" unless defined $job;
if ($job->busy != 0 && $job->locker != getppid) {
die "job $jobId is already being built";
($build) = $db->resultset('Builds')->search({id => $buildId});
die "build $buildId doesn't exist" unless defined $build;
if ($build->schedulingInfo->busy != 0 && $build->schedulingInfo->locker != getppid) {
die "build $buildId is already being built";
create table builds (
-- This table contains all builds, either scheduled or finished. For
-- scheduled builds, additional info (such as the priority) can be
-- found in the BuildSchedulingInfo table. For finished builds,
-- additional info (such as the logs, build products, etc.) can be
-- found in several tables, such as BuildResultInfo, BuildLogs and
-- BuildProducts.
create table Builds (
system text not null,
foreign key (project) references Projects(name), -- ignored by sqlite
foreign key (project, jobset) references Jobsets(project, name) -- ignored by sqlite
);
-- Info for a scheduled build.
create table BuildSchedulingInfo (
id integer primary key not null,
priority integer not null default 0,
busy integer not null default 0, -- true means someone is building this job now
locker text not null default '', -- !!! hostname/pid of the process building this job?
logfile text, -- if busy, the path of the logfile
foreign key (id) references Builds(id) on delete cascade -- ignored by sqlite
);
-- Info for a finished build.
create table BuildResultInfo (
id integer primary key not null,
foreign key (build) references builds(id) -- ignored by sqlite
foreign key (job) references jobs(id) -- ignored by sqlite
foreign key (dependency) references builds(id) -- ignored by sqlite
foreign key (build) references Builds(id) on delete cascade, -- ignored by sqlite
foreign key (dependency) references Builds(id) -- ignored by sqlite
--delete from buildInputs where build = old.id;
delete from buildLogs where build = old.id;
delete from buildProducts where build = old.id;
delete from BuildSchedulingInfo where id = old.id;
delete from BuildResultInfo where id = old.id;
delete from BuildInputs where build = old.id;
delete from BuildLogs where build = old.id;
delete from BuildProducts where build = old.id;
foreign key (project) references projects(name) on delete cascade, -- ignored by sqlite
foreign key (project, name, nixExprInput) references jobsetInputs(project, job, name)
foreign key (project) references Projects(name) on delete cascade, -- ignored by sqlite
foreign key (project, name, nixExprInput) references JobsetInputs(project, job, name)
foreign key (project, jobset, input) references jobsetInputs(project, jobset, name) on delete cascade -- ignored by sqlite
);
create table jobs (
id integer primary key autoincrement not null,
timestamp integer not null, -- time this build was added to the db (in Unix time)
priority integer not null default 0,
busy integer not null default 0, -- true means someone is building this job now
locker text not null default '', -- !!! hostname/pid of the process building this job?
-- Info about the inputs.
project text not null, -- !!! foreign key
jobset text not null, -- !!! foreign key
attrName text not null,
-- What this job will build.
description text,
drvPath text not null,
outPath text not null,
system text not null,
foreign key (project) references projects(name), -- ignored by sqlite
foreign key (project, jobset) references jobsets(project, name) -- ignored by sqlite
foreign key (project, jobset, input) references JobsetInputs(project, jobset, name) on delete cascade -- ignored by sqlite
{project => $project->name, jobset => $jobset->name, attrname => $argName, buildStatus => 0},
{order_by => "timestamp DESC", rows => 1});
{finished => 1, project => $project->name, jobset => $jobset->name, attrname => $argName, buildStatus => 0},
{join => 'resultInfo', order_by => "timestamp DESC", rows => 1});