diff --git a/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm b/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm
index f5100ea5..b68aa9ff 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm
@@ -37,7 +37,7 @@ sub index :Path :Args(0) {
# 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)"
+ , where => "finished != 0 and timestamp = (select max(timestamp) from Builds where project == me.project and attrName == me.attrName and finished != 0)"
, order_by => "project, attrname"
})];
}
@@ -106,6 +106,24 @@ sub log :Local {
}
+sub nixlog :Local {
+ my ( $self, $c, $id, $stepnr ) = @_;
+
+ my $build = getBuild($c, $id);
+ return error($c, "Build with ID $id doesn't exist.") if !defined $build;
+
+ my $step = $build->buildsteps->find({stepnr => $stepnr});
+ return error($c, "Build $id doesn't have a build step $stepnr.") if !defined $step;
+
+ $c->stash->{template} = 'log.tt';
+ $c->stash->{id} = $id;
+ $c->stash->{step} = $step;
+
+ # !!! should be done in the view (as a TT plugin).
+ $c->stash->{logtext} = loadLog($step->logfile);
+}
+
+
sub loadLog {
my ($path) = @_;
# !!! all a quick hack
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema.pm b/src/HydraFrontend/lib/HydraFrontend/Schema.pm
index 052fc9cf..1a381468 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema.pm
@@ -8,8 +8,8 @@ use base 'DBIx::Class::Schema';
__PACKAGE__->load_classes;
-# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1AgCf4sf5h2RU24Slo0sTA
+# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:gS2Lp7T6IZ160iYQbEhd+g
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildinputs.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildinputs.pm
index eda11d4d..6b96dd61 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildinputs.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildinputs.pm
@@ -38,8 +38,8 @@ __PACKAGE__->belongs_to(
);
-# 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-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:MtL3cwH9upjNmhaZkGszRA
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildlogs.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildlogs.pm
index 2f21bb8f..2d67b001 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildlogs.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildlogs.pm
@@ -21,8 +21,8 @@ __PACKAGE__->set_primary_key("build", "logphase");
__PACKAGE__->belongs_to("build", "HydraFrontend::Schema::Builds", { id => "build" });
-# 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-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vvyGq3BeKyyK7K6uDxJHyQ
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildproducts.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildproducts.pm
index 22ef546a..ff1f4cf3 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildproducts.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildproducts.pm
@@ -21,8 +21,8 @@ __PACKAGE__->set_primary_key("build", "path");
__PACKAGE__->belongs_to("build", "HydraFrontend::Schema::Builds", { id => "build" });
-# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:rZPTilX/PAiIoxffxc0nJw
+# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:et00AvSBi5LZUoIrIUOKFQ
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildresultinfo.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildresultinfo.pm
index 1125256d..d14fd269 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildresultinfo.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildresultinfo.pm
@@ -25,8 +25,8 @@ __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
+# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:8zXrs7iT2h3xp6C/2q37uQ
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Builds.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Builds.pm
index 92d358d6..5f393542 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Builds.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Builds.pm
@@ -70,10 +70,15 @@ __PACKAGE__->has_many(
"HydraFrontend::Schema::Buildlogs",
{ "foreign.build" => "self.id" },
);
+__PACKAGE__->has_many(
+ "buildsteps",
+ "HydraFrontend::Schema::Buildsteps",
+ { "foreign.id" => "self.id" },
+);
-# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 13:41:38
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1GZeB3YVr064AZrGargmFg
+# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:c8feWTpKijITXXSdJICuFg
__PACKAGE__->has_many(dependents => 'HydraFrontend::Schema::Buildinputs', 'dependency');
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildschedulinginfo.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildschedulinginfo.pm
index 851a75b0..3f521f67 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildschedulinginfo.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildschedulinginfo.pm
@@ -23,8 +23,8 @@ __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
+# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Z65HteUghCT7sXfXpsHYXg
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Buildsteps.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildsteps.pm
new file mode 100644
index 00000000..21064ad8
--- /dev/null
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Buildsteps.pm
@@ -0,0 +1,43 @@
+package HydraFrontend::Schema::Buildsteps;
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components("Core");
+__PACKAGE__->table("BuildSteps");
+__PACKAGE__->add_columns(
+ "id",
+ { data_type => "integer", is_nullable => 0, size => undef },
+ "stepnr",
+ { data_type => "integer", is_nullable => 0, size => undef },
+ "type",
+ { data_type => "integer", is_nullable => 0, size => undef },
+ "drvpath",
+ { data_type => "text", is_nullable => 0, size => undef },
+ "outpath",
+ { data_type => "text", is_nullable => 0, size => undef },
+ "logfile",
+ { data_type => "text", is_nullable => 0, size => undef },
+ "busy",
+ { data_type => "integer", is_nullable => 0, size => undef },
+ "status",
+ { 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", "stepnr");
+__PACKAGE__->belongs_to("id", "HydraFrontend::Schema::Builds", { id => "id" });
+
+
+# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:GmvM5Rhj4MY7eNQpqTz7bw
+
+
+# You can replace this text with custom content, and it will be preserved on regeneration
+1;
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputalts.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputalts.pm
index f7603979..35013dce 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputalts.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputalts.pm
@@ -33,8 +33,8 @@ __PACKAGE__->belongs_to(
);
-# 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-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:mng7GAPMDxsznKupYdhwQw
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputs.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputs.pm
index 61bfcfd3..71f22994 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputs.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsetinputs.pm
@@ -43,8 +43,8 @@ __PACKAGE__->has_many(
);
-# 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-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vEXBbzKUTBQmGmL8uh9mIA
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsets.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsets.pm
index 06f0d939..ca2c3c32 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsets.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Jobsets.pm
@@ -48,8 +48,8 @@ __PACKAGE__->has_many(
);
-# 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-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hMYI8zT3UB/k9IbddK1X4g
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/lib/HydraFrontend/Schema/Projects.pm b/src/HydraFrontend/lib/HydraFrontend/Schema/Projects.pm
index 564297e5..bc10b085 100644
--- a/src/HydraFrontend/lib/HydraFrontend/Schema/Projects.pm
+++ b/src/HydraFrontend/lib/HydraFrontend/Schema/Projects.pm
@@ -24,8 +24,8 @@ __PACKAGE__->has_many(
);
-# 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-11 18:02:00
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1DTnCjRw929OuAfeJ5gsXA
# You can replace this text with custom content, and it will be preserved on regeneration
diff --git a/src/HydraFrontend/root/build.tt b/src/HydraFrontend/root/build.tt
index b824a0c9..09838701 100644
--- a/src/HydraFrontend/root/build.tt
+++ b/src/HydraFrontend/root/build.tt
@@ -33,10 +33,10 @@
Success
[% ELSIF build.resultInfo.buildstatus == 1 %]
- Build returned a non-zero exit code
+ Build returned a non-zero exit code
[% ELSE %]
- Build failed
+ Build failed
[% END %]
[% ELSIF build.schedulingInfo.busy %]
Build in progress
@@ -134,6 +134,39 @@
+[% IF build.buildsteps %]
+
+
| Nr | What | Status |
|---|---|---|
| [% step.stepnr %] | ++ Build of [% step.outpath %] + | ++ [% IF step.busy == 1 %] + Building + [% ELSIF step.status == 0 %] + Succeeded + [% ELSE %] + Failed: [% step.errormsg %] + [% END %] + (log) + | +
diff --git a/src/build.pl b/src/build.pl
index 1a4dfae8..08e71d17 100644
--- a/src/build.pl
+++ b/src/build.pl
@@ -32,7 +32,66 @@ sub doBuild {
$startTime = time();
- my $res = system("nix-store --realise $drvPath");
+ # Run Nix to perform the build, and monitor the stderr output
+ # to get notifications about specific build steps, the
+ # associated log files, etc.
+ my $cmd = "nix-store --keep-going --no-build-output " .
+ "--log-type flat --print-build-trace --realise $drvPath 2>&1";
+
+ my $buildStepNr = 1;
+
+ open OUT, "$cmd |" or die;
+
+ while () {
+ unless (/^@\s+/) {
+ print STDERR "$_";
+ next;
+ }
+ print STDERR "GOT $_";
+
+ if (/^@\s+build-started\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/) {
+ $db->txn_do(sub {
+ $db->resultset('Buildsteps')->create(
+ { id => $build->id
+ , stepnr => $buildStepNr++
+ , type => 0 # = build
+ , drvpath => $1
+ , outpath => $2
+ , logfile => $4
+ , busy => 1
+ });
+ });
+ }
+
+ if (/^@\s+build-succeeded\s+(\S+)\s+(\S+)$/) {
+ $db->txn_do(sub {
+ my $drvPath = $1;
+ (my $step) = $db->resultset('Buildsteps')->search(
+ {id => $build->id, type => 0, drvpath => $drvPath}, {});
+ die unless $step;
+ $step->busy(0);
+ $step->status(0);
+ $step->update;
+ });
+ }
+
+ if (/^@\s+build-failed\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
+ $db->txn_do(sub {
+ my $drvPath = $1;
+ (my $step) = $db->resultset('Buildsteps')->search(
+ {id => $build->id, type => 0, drvpath => $drvPath}, {});
+ die unless $step;
+ $step->busy(0);
+ $step->status(1);
+ $step->errormsg($4);
+ $step->update;
+ });
+ }
+ }
+
+ close OUT;
+
+ my $res = $?;
$stopTime = time();
@@ -64,7 +123,7 @@ sub doBuild {
my $logPath = "/nix/var/log/nix/drvs/" . basename $drvPath;
if (-e $logPath) {
- print "found log $logPath\n";
+ print STDERR "found log $logPath\n";
$db->resultset('Buildlogs')->create(
{ build => $build->id
, logphase => "full"
@@ -77,7 +136,7 @@ sub doBuild {
if (-e "$outPath/log") {
foreach my $logPath (glob "$outPath/log/*") {
- print "found log $logPath\n";
+ print STDERR "found log $logPath\n";
$db->resultset('Buildlogs')->create(
{ build => $build->id
, logphase => basename($logPath)
@@ -119,7 +178,7 @@ sub doBuild {
my $buildId = $ARGV[0] or die;
-print "performing build $buildId\n";
+print STDERR "performing build $buildId\n";
# Lock the build. If necessary, steal the lock from the parent
# process (runner.pl). This is so that if the runner dies, the
diff --git a/src/hydra.sql b/src/hydra.sql
index bd3b6d7c..d000b7ff 100644
--- a/src/hydra.sql
+++ b/src/hydra.sql
@@ -59,6 +59,31 @@ create table BuildResultInfo (
);
+create table BuildSteps (
+ id integer not null,
+ stepnr integer not null,
+
+ type integer not null, -- 0 = build, 1 = substitution
+
+ drvPath text,
+ outPath text,
+
+ logfile text,
+
+ busy integer not null,
+
+ status integer,
+
+ errorMsg text,
+
+ startTime integer, -- in Unix time, 0 = used cached build result
+ stopTime integer,
+
+ primary key (id, stepnr),
+ foreign key (id) references Builds(id) on delete cascade -- ignored by sqlite
+);
+
+
-- Inputs of builds.
create table BuildInputs (
id integer primary key autoincrement not null,
diff --git a/src/runner.pl b/src/runner.pl
index 394ed1d0..438de2c9 100644
--- a/src/runner.pl
+++ b/src/runner.pl
@@ -16,7 +16,6 @@ $db->txn_do(sub {
my @jobs = $db->resultset('Builds')->search(
{finished => 0, busy => 1}, {join => 'schedulingInfo'});
foreach my $job (@jobs) {
- print $job, "\n";
my $pid = $job->schedulingInfo->locker;
if (kill(0, $pid) != 1) { # see if we can signal the process
print "job ", $job->id, " pid $pid died, unlocking\n";