diff --git a/subprojects/hydra/lib/Hydra/Controller/Build.pm b/subprojects/hydra/lib/Hydra/Controller/Build.pm index ca9a22cff..43cd0a8f6 100644 --- a/subprojects/hydra/lib/Hydra/Controller/Build.pm +++ b/subprojects/hydra/lib/Hydra/Controller/Build.pm @@ -6,6 +6,7 @@ use warnings; use base 'Hydra::Base::Controller::NixChannel'; use Hydra::Helper::Nix; use Hydra::Helper::CatalystUtils; +use Hydra::Helper::LogEndpoints; use File::Basename; use File::LibMagic; use File::stat; @@ -133,17 +134,13 @@ sub constituents_GET { } -sub view_nixlog : Chained('buildChain') PathPart('nixlog') { +# Redirect old /build/:id/nixlog/:stepnr[/:mode] URLs to new canonical paths +sub nixlog_redirect : Chained('buildChain') PathPart('nixlog') { my ($self, $c, $stepnr, $mode) = @_; - my $step = $c->stash->{build}->buildsteps->find({stepnr => $stepnr}); - notFound($c, "Build doesn't have a build step $stepnr.") if !defined $step; - - $c->stash->{step} = $step; - - my $drvPath = $step->drvpath; - my $log_uri = $c->uri_for($c->controller('Root')->action_for("log"), [WWW::Form::UrlEncoded::PP::url_encode(basename($drvPath))]); - showLog($c, $mode, $log_uri); + my @path = ('/build', $c->stash->{id}, 'step', $stepnr, 'log'); + push @path, $mode if defined $mode; + $c->res->redirect($c->uri_for(@path), 301); } @@ -166,32 +163,6 @@ sub view_runcommandlog : Chained('buildChain') PathPart('runcommandlog') { } -sub showLog { - my ($c, $mode, $log_uri) = @_; - $mode //= "pretty"; - - if ($mode eq "pretty") { - $c->stash->{log_uri} = $log_uri; - $c->stash->{template} = 'log.tt'; - } - - elsif ($mode eq "raw") { - $c->res->redirect($log_uri); - } - - elsif ($mode eq "tail") { - my $lines = 50; - $c->stash->{log_uri} = $log_uri . "?tail=$lines"; - $c->stash->{tail} = $lines; - $c->stash->{template} = 'log.tt'; - } - - else { - error($c, "Unknown log display mode '$mode'."); - } -} - - sub defaultUriForProduct { my ($self, $c, $product, @path) = @_; my $x = $product->productnr diff --git a/subprojects/hydra/lib/Hydra/Controller/BuildStep.pm b/subprojects/hydra/lib/Hydra/Controller/BuildStep.pm new file mode 100644 index 000000000..6ba585601 --- /dev/null +++ b/subprojects/hydra/lib/Hydra/Controller/BuildStep.pm @@ -0,0 +1,38 @@ +package Hydra::Controller::BuildStep; + +use utf8; +use strict; +use warnings; +use base 'Hydra::Base::Controller::REST'; +use Hydra::Helper::CatalystUtils; +use Hydra::Helper::LogEndpoints; +use File::Basename; +use WWW::Form::UrlEncoded::PP qw(); + + +sub buildStepChain :Chained('/build/buildChain') :PathPart('step') :CaptureArgs(1) { + my ($self, $c, $stepnr) = @_; + + my $step = $c->stash->{build}->buildsteps->find({stepnr => $stepnr}); + notFound($c, "Build doesn't have a build step $stepnr.") if !defined $step; + + $c->stash->{step} = $step; +} + + +sub buildStep : Chained('buildStepChain') PathPart('') Args(0) { + my ($self, $c) = @_; + $c->stash->{template} = 'build-step.tt'; +} + + +sub view_nixlog : Chained('buildStepChain') PathPart('log') { + my ($self, $c, $mode) = @_; + + my $drvPath = $c->stash->{step}->drvpath; + my $log_uri = $c->uri_for($c->controller('Root')->action_for("log"), [WWW::Form::UrlEncoded::PP::url_encode(basename($drvPath))]); + showLog($c, $mode, $log_uri); +} + + +1; diff --git a/subprojects/hydra/lib/Hydra/Helper/LogEndpoints.pm b/subprojects/hydra/lib/Hydra/Helper/LogEndpoints.pm new file mode 100644 index 000000000..685737498 --- /dev/null +++ b/subprojects/hydra/lib/Hydra/Helper/LogEndpoints.pm @@ -0,0 +1,36 @@ +package Hydra::Helper::LogEndpoints; + +use strict; +use warnings; +use Exporter; +use Hydra::Helper::CatalystUtils; + +our @ISA = qw(Exporter); +our @EXPORT = qw(showLog); + +sub showLog { + my ($c, $mode, $log_uri) = @_; + $mode //= "pretty"; + + if ($mode eq "pretty") { + $c->stash->{log_uri} = $log_uri; + $c->stash->{template} = 'log.tt'; + } + + elsif ($mode eq "raw") { + $c->res->redirect($log_uri); + } + + elsif ($mode eq "tail") { + my $lines = 50; + $c->stash->{log_uri} = $log_uri . "?tail=$lines"; + $c->stash->{tail} = $lines; + $c->stash->{template} = 'log.tt'; + } + + else { + error($c, "Unknown log display mode '$mode'."); + } +} + +1; diff --git a/subprojects/hydra/root/build-common.tt b/subprojects/hydra/root/build-common.tt new file mode 100644 index 000000000..a26e88937 --- /dev/null +++ b/subprojects/hydra/root/build-common.tt @@ -0,0 +1,79 @@ +[% BLOCK renderLogButtons %] + url) %]>pretty + url _ "/raw") %]>raw + url _ "/tail") %]>tail +[% END %] + +[% BLOCK renderOutputs %] + [% start=1; FOREACH output IN outputs %] + [% IF !start %],
[% END; start=0; output.path %] + [% END %] +[% END %] + +[% BLOCK renderOutputsTable %] + + [% FOREACH output IN outputs %] + + + + + [% END %] +
[% output.name | html %][% IF output.path; output.path | html; ELSE %]n/a[% END %]
+[% END; %] + +[% BLOCK renderStepDuration %] + [% IF step.busy == 0 %] + [% IF step.stoptime %] + [% INCLUDE renderDuration duration = step.stoptime - step.starttime %] + [% ELSE %] + n/a + [% END %] + [% ELSIF build.finished %] + [% INCLUDE renderDuration duration = build.stoptime - step.starttime %] + [% ELSE %] + [% INCLUDE renderDuration duration = curTime - step.starttime %] + [% END %] +[% END %] + +[% BLOCK renderStepMachine %] + [% IF step.busy != 0 || ((step.machine || step.starttime) && (step.status == 0 || step.status == 1 || step.status == 3 || step.status == 4 || step.status == 7)) %] + [% INCLUDE renderMachineName machine=step.machine %] + [% ELSE %] + n/a + [% END %] +[% END %] + +[% BLOCK renderStepStatus %] + [% IF step.busy != 0 %] + [% INCLUDE renderBusyStatus %] + [% ELSIF step.status == 0 %] + [% IF step.isnondeterministic %] + Succeeded with non-determistic result + [% ELSE %] + Succeeded + [% END %] + [% IF step.timesbuilt && step.timesbuilt > 1 %] + ([% step.timesbuilt %] times) + [% END %] + [% ELSIF step.status == 3 %] + Aborted[% IF step.errormsg %]: [% HTML.escape(step.errormsg) %][% END %] + [% ELSIF step.status == 4 %] + Cancelled + [% ELSIF step.status == 7 %] + Timed out + [% ELSIF step.status == 8 %] + Cached failure + [% ELSIF step.status == 9 %] + Unsupported system type + [% ELSIF step.status == 10 %] + Log limit exceeded + [% ELSIF step.status == 11 %] + Output limit exceeded + [% ELSIF step.status == 12 %] + Non-determinism detected[% IF step.timesbuilt %] after [% HTML.escape(step.timesbuilt) %] times[% END %] + [% ELSIF step.errormsg %] + Failed: [% HTML.escape(step.errormsg) %] + [% ELSE %] + Failed + [% END %] +[% END %] diff --git a/subprojects/hydra/root/build-step.tt b/subprojects/hydra/root/build-step.tt new file mode 100644 index 000000000..38ce9a906 --- /dev/null +++ b/subprojects/hydra/root/build-step.tt @@ -0,0 +1,61 @@ +[% + buildUrl = c.uri_for('/build', build.id); +%] +[% WRAPPER layout.tt + title="Step ${step.stepnr} of build ${build.id} of job " _ makeNameTextForJob(build.jobset, job) + titleHTML="Step ${step.stepnr}" + _ " of build ${build.id}" + _ " of job " _ linkToJob(build.jobset, job) +%] +[% PROCESS common.tt %] +[% PROCESS "build-common.tt" %] +[% USE HTML %] + +[% logUrl = c.uri_for('/build' build.id 'step' step.stepnr 'log') %] +[% has_log = buildStepLogExists(step) %] + + + + + + + + + + + + + + + [% IF step.system %] + + + + + [% END %] + + + + + + + + + + + + + [% IF has_log %] + + + + + [% END %] +
Type:[% IF step.type == 0 %]Build[% ELSE %]Substitution[% END %]
Derivation:[% step.drvpath | html %]
Output store paths:[% INCLUDE renderOutputsTable outputs=step.buildstepoutputs %]
System:[% step.system | html %]
Machine:[% INCLUDE renderStepMachine %]
Duration:[% INCLUDE renderStepDuration %]
Status: + [% INCLUDE renderStepStatus %] + [% IF step.propagatedfrom %] + (propagated from [% INCLUDE renderBuildIdLink id=step.propagatedfrom.get_column('id') %]) + [% END %] +
Logfile:[% INCLUDE renderLogButtons url=logUrl %]
+ +[% END %] diff --git a/subprojects/hydra/root/build.tt b/subprojects/hydra/root/build.tt index 23fc5493b..3263b1101 100644 --- a/subprojects/hydra/root/build.tt +++ b/subprojects/hydra/root/build.tt @@ -3,6 +3,7 @@ titleHTML="Build $id of job " _ linkToJob(jobset, job) %] [% PROCESS common.tt %] +[% PROCESS "build-common.tt" %] [% PROCESS "product-list.tt" %] [% USE HTML %] [% USE Date %] @@ -19,23 +20,6 @@ FOR step IN steps; END; %] -[% BLOCK renderOutputs %] - [% start=1; FOREACH output IN outputs %] - [% IF !start %],
[% END; start=0; output.path %] - [% END %] -[% END %] - -[% BLOCK renderOutputsTable %] - - [% FOREACH output IN outputs %] - - - - - [% END %] -
[% output.name | html %][% IF output.path; output.path | html; ELSE %]n/a[% END %]
-[% END; %] - [% BLOCK renderBuildSteps %] @@ -46,9 +30,10 @@ END; [% IF ( type == "All" ) || ( type == "Failed" && step.busy == 0 && step.status != 0 ) || ( type == "Running" && step.busy != 0 ) %] [% has_log = seen.${step.drvpath} ? 0 : buildStepLogExists(step); seen.${step.drvpath} = 1; - log = c.uri_for('/build' build.id 'nixlog' step.stepnr); %] + stepUrl = c.uri_for('/build' build.id 'step' step.stepnr); + logUrl = c.uri_for('/build' build.id 'step' step.stepnr 'log'); %] - + - - + + @@ -236,10 +178,8 @@ END; [% END %] @@ -542,11 +482,7 @@ END; [% END %] [% IF runcommandlog.uuid != undef %] [% runLog = c.uri_for('/build', build.id, 'runcommandlog', runcommandlog.uuid) %] -
- runLog) %]>pretty - runLog) %]/raw">raw - runLog) %]/tail">tail -
+
[% INCLUDE renderLogButtons url=runLog %]
[% END %] [% ELSE %] diff --git a/subprojects/hydra/root/deps.tt b/subprojects/hydra/root/deps.tt index 4cb49af49..91a08335d 100644 --- a/subprojects/hydra/root/deps.tt +++ b/subprojects/hydra/root/deps.tt @@ -13,7 +13,7 @@ [% IF node.buildStep %] c.uri_for('/build' node.buildStep.get_column('build'))) %]>[% node.name %] [% IF buildStepLogExists(node.buildStep); - INCLUDE renderLogLinks url=c.uri_for('/build' node.buildStep.get_column('build') 'nixlog' node.buildStep.stepnr); + INCLUDE renderLogLinks url=c.uri_for('/build' node.buildStep.get_column('build') 'step' node.buildStep.stepnr 'log'); END %] [% ELSE %] [% node.name | html %] (no info) diff --git a/subprojects/hydra/root/log.tt b/subprojects/hydra/root/log.tt index 999c849e0..164a964c7 100644 --- a/subprojects/hydra/root/log.tt +++ b/subprojects/hydra/root/log.tt @@ -1,10 +1,11 @@ [% buildUrl = c.uri_for('/build', build.id); IF step; - logUrl = c.uri_for('/build', build.id, 'nixlog', step.stepnr); + stepUrl = c.uri_for('/build', build.id, 'step', step.stepnr); + logUrl = c.uri_for('/build', build.id, 'step', step.stepnr, 'log'); drvpath = step.drvpath; titleText = "Log of step ${step.stepnr} of build ${build.id} of job " _ makeNameTextForJob(build.jobset, job); - titleLink = "Log of step ${step.stepnr}" + titleLink = "Log of step ${step.stepnr}" _ " of build ${build.id}" _ " of job " _ linkToJob(build.jobset, job); ELSE; diff --git a/subprojects/hydra/root/machine-status.tt b/subprojects/hydra/root/machine-status.tt index e8113beaf..fa777f93a 100644 --- a/subprojects/hydra/root/machine-status.tt +++ b/subprojects/hydra/root/machine-status.tt @@ -77,7 +77,7 @@ - + diff --git a/subprojects/hydra/root/steps.tt b/subprojects/hydra/root/steps.tt index e53a41b70..703226a65 100644 --- a/subprojects/hydra/root/steps.tt +++ b/subprojects/hydra/root/steps.tt @@ -25,7 +25,7 @@ order of descending finish time.

- +
[% HTML.escape(step.stepnr) %] stepUrl) %]>[% HTML.escape(step.stepnr) %] [% IF step.type == 0 %] Build of [% INCLUDE renderOutputs outputs=step.buildstepoutputs %] @@ -56,54 +41,11 @@ END; Substitution of [% INCLUDE renderOutputs outputs=step.buildstepoutputs %] [% END %] - [% IF step.busy == 0; - IF step.stoptime; - INCLUDE renderDuration duration = step.stoptime - step.starttime; - ELSE; - %]n/a[% - END; - ELSIF build.finished; - INCLUDE renderDuration duration = build.stoptime - step.starttime; - ELSE; - INCLUDE renderDuration duration = curTime - step.starttime; - END %] - [% IF step.busy != 0 || ((step.machine || step.starttime) && (step.status == 0 || step.status == 1 || step.status == 3 || step.status == 4 || step.status == 7)); INCLUDE renderMachineName machine=step.machine; ELSE; "n/a"; END %][% INCLUDE renderStepDuration %][% INCLUDE renderStepMachine %] - [% IF step.busy != 0 %] - [% INCLUDE renderBusyStatus %] - [% ELSIF step.status == 0 %] - [% IF step.isnondeterministic %] - Succeeded with non-determistic result - [% ELSE %] - Succeeded - [% END %] - [% IF step.timesbuilt && step.timesbuilt > 1 %] - ([% step.timesbuilt %] times) - [% END %] - [% ELSIF step.status == 3 %] - Aborted[% IF step.errormsg %]: [% HTML.escape(step.errormsg) %][% END %] - [% ELSIF step.status == 4 %] - Cancelled - [% ELSIF step.status == 7 %] - Timed out - [% ELSIF step.status == 8 %] - Cached failure - [% ELSIF step.status == 9 %] - Unsupported system type - [% ELSIF step.status == 10 %] - Log limit exceeded - [% ELSIF step.status == 11 %] - Output limit exceeded - [% ELSIF step.status == 12 %] - Non-determinism detected [% IF step.timesbuilt %] after [% HTML.escape(step.timesbuilt) %] times[% END %] - [% ELSIF step.errormsg %] - Failed: [% HTML.escape(step.errormsg) %] - [% ELSE %] - Failed - [% END %] - [%%] [%+ IF has_log; INCLUDE renderLogLinks url=log inRow=1; END %] + [% INCLUDE renderStepStatus %] + [%%] [%+ IF has_log; INCLUDE renderLogLinks url=logUrl; END %] [%+ IF step.propagatedfrom; %](propagated from [% INCLUDE renderBuildIdLink id=step.propagatedfrom.get_column('id') %])[% END %]
Logfile: - [% actualLog = cachedBuildStep ? c.uri_for('/build' cachedBuild.id 'nixlog' cachedBuildStep.stepnr) : c.uri_for('/build' build.id 'log') %] - actualLog) %]>pretty - actualLog _ "/raw") %]>raw - actualLog _ "/tail") %]>tail + [% actualLog = cachedBuildStep ? c.uri_for('/build' cachedBuild.id 'step' cachedBuildStep.stepnr 'log') : c.uri_for('/build' build.id 'log') %] + [% INCLUDE renderLogButtons url=actualLog %]
[% INCLUDE renderFullJobName project=step.project jobset=step.jobset job=step.job %] c.uri_for('/build' step.build)) %]>[% HTML.escape(step.build) %][% IF step.busy >= 30 %] c.uri_for('/build' step.build 'nixlog' step.stepnr 'tail')) %]>[% HTML.escape(step.stepnr) %][% ELSE; HTML.escape(step.stepnr); END %][% IF step.busy >= 30 %] c.uri_for('/build' step.build 'step' step.stepnr 'log' 'tail')) %]>[% HTML.escape(step.stepnr) %][% ELSE; HTML.escape(step.stepnr); END %] [% step.drvpath.match('-(.*)').0 | html %] [% INCLUDE renderBusyStatus %] [% INCLUDE renderDuration duration = curTime - step.starttime %] [% step.drvpath.match('-(.*).drv').0 %] [% INCLUDE renderFullJobNameOfBuild build=step.build %] c.uri_for('/build' step.build.id)) %]>[% HTML.escape(step.build.id) %] c.uri_for('/build' step.build.id 'nixlog' step.stepnr 'tail')) %]>[% HTML.escape(step.stepnr) %] c.uri_for('/build' step.build.id 'step' step.stepnr 'log' 'tail')) %]>[% HTML.escape(step.stepnr) %] [% INCLUDE renderRelativeDate timestamp=step.stoptime %] [% INCLUDE renderDuration duration = step.stoptime - step.starttime %] [% INCLUDE renderMachineName machine=step.machine %]