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";