From 0ec03aa0f497f776afbd875f3f36100921f7c660 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 7 Oct 2013 17:06:17 +0200 Subject: [PATCH] Handle builds with multiple outputs correctly in Hydra channels --- src/lib/Hydra/Base/Controller/ListBuilds.pm | 1 + src/lib/Hydra/Base/Controller/NixChannel.pm | 44 ++++++++---- src/lib/Hydra/Controller/JobsetEval.pm | 1 + src/lib/Hydra/View/NixExprs.pm | 77 +++++++++++++++------ src/root/channel-contents.tt | 1 - 5 files changed, 88 insertions(+), 36 deletions(-) diff --git a/src/lib/Hydra/Base/Controller/ListBuilds.pm b/src/lib/Hydra/Base/Controller/ListBuilds.pm index 89a22ce4..b971d5e8 100644 --- a/src/lib/Hydra/Base/Controller/ListBuilds.pm +++ b/src/lib/Hydra/Base/Controller/ListBuilds.pm @@ -41,6 +41,7 @@ sub nix : Chained('get_builds') PathPart('channel') CaptureArgs(1) { ->search_literal("exists (select 1 from buildproducts where build = me.id and type = 'nix-build')") ->search({}, { columns => [@buildListColumns, 'drvpath', 'description', 'homepage'] , join => ["buildoutputs"] + , order_by => ["me.id", "buildoutputs.name"] , '+select' => ['buildoutputs.path', 'buildoutputs.name'], '+as' => ['outpath', 'outname'] }); } else { diff --git a/src/lib/Hydra/Base/Controller/NixChannel.pm b/src/lib/Hydra/Base/Controller/NixChannel.pm index 40aedaa0..6452f279 100644 --- a/src/lib/Hydra/Base/Controller/NixChannel.pm +++ b/src/lib/Hydra/Base/Controller/NixChannel.pm @@ -14,20 +14,36 @@ sub getChannelData { my @storePaths = (); $c->stash->{nixPkgs} = []; - foreach my $build ($c->stash->{channelBuilds}->all) { - my $outPath = $build->get_column("outpath"); - my $outName = $build->get_column("outname"); - next if $checkValidity && !isValidPath($outPath); - push @storePaths, $outPath; - my $pkgName = $build->nixname . "-" . $build->system . "-" . $build->id . ($outName ne "out" ? "-" . $outName : ""); - push @{$c->stash->{nixPkgs}}, { build => $build, name => $pkgName, outPath => $outPath, outName => $outName }; - # Put the system type in the manifest (for top-level paths) as - # a hint to the binary patch generator. (It shouldn't try to - # generate patches between builds for different systems.) It - # would be nice if Nix stored this info for every path but it - # doesn't. - $c->stash->{systemForPath}->{$outPath} = $build->system; - }; + + my @builds = $c->stash->{channelBuilds}->all; + + for (my $n = 0; $n < scalar @builds; ) { + # Since channelData is a join of Builds and BuildOutputs, we + # need to gather the rows that belong to a single build. + my $build = $builds[$n++]; + my @outputs = ($build); + push @outputs, $builds[$n++] while $n < scalar @builds && $builds[$n]->id == $build->id; + @outputs = grep { $_->get_column("outpath") } @outputs; + + my $outputs = {}; + foreach my $output (@outputs) { + my $outPath = $output->get_column("outpath"); + next if $checkValidity && !isValidPath($outPath); + $outputs->{$output->get_column("outname")} = $outPath; + push @storePaths, $outPath; + # Put the system type in the manifest (for top-level + # paths) as a hint to the binary patch generator. (It + # shouldn't try to generate patches between builds for + # different systems.) It would be nice if Nix stored this + # info for every path but it doesn't. + $c->stash->{systemForPath}->{$outPath} = $build->system; + } + + next if !%$outputs; + + my $pkgName = $build->nixname . "-" . $build->system . "-" . $build->id; + push @{$c->stash->{nixPkgs}}, { build => $build, name => $pkgName, outputs => $outputs }; + } $c->stash->{storePaths} = [@storePaths]; } diff --git a/src/lib/Hydra/Controller/JobsetEval.pm b/src/lib/Hydra/Controller/JobsetEval.pm index 40b52cb3..74ab3bce 100644 --- a/src/lib/Hydra/Controller/JobsetEval.pm +++ b/src/lib/Hydra/Controller/JobsetEval.pm @@ -182,6 +182,7 @@ sub nix : Chained('eval') PathPart('channel') CaptureArgs(0) { ->search({ finished => 1, buildstatus => 0 }, { columns => [@buildListColumns, 'drvpath', 'description', 'homepage'] , join => ["buildoutputs"] + , order_by => ["build.id", "buildoutputs.name"] , '+select' => ['buildoutputs.path', 'buildoutputs.name'], '+as' => ['outpath', 'outname'] }); } diff --git a/src/lib/Hydra/View/NixExprs.pm b/src/lib/Hydra/View/NixExprs.pm index 1faf9e25..25c06b2e 100644 --- a/src/lib/Hydra/View/NixExprs.pm +++ b/src/lib/Hydra/View/NixExprs.pm @@ -23,34 +23,69 @@ sub process { foreach my $pkg (@{$c->stash->{nixPkgs}}) { my $build = $pkg->{build}; - my $s = ""; - $s .= " # $pkg->{name}\n"; - $s .= " ${\escape $build->get_column('job')} = {\n"; - $s .= " type = \"derivation\";\n"; - $s .= " name = ${\escape ($build->get_column('releasename') or $build->nixname)};\n"; - $s .= " system = ${\escape $build->system};\n"; - $s .= " outPath = ${\escape $pkg->{outPath}};\n"; - $s .= " meta = {\n"; - $s .= " description = ${\escape $build->description};\n" - if $build->description; - $s .= " longDescription = ${\escape $build->longdescription};\n" - if $build->longdescription; - $s .= " license = ${\escape $build->license};\n" - if $build->license; - $s .= " maintainers = ${\escape $build->maintainers};\n" - if $build->maintainers; - $s .= " };\n"; - $s .= " };\n\n"; - $perSystem{$build->system} .= $s; + $perSystem{$build->system}->{$build->get_column('job')} = $pkg; } - my $res = "{ system ? builtins.currentSystem }:\n\n"; + my $res = <{$job}; + my $build = $pkg->{build}; + $res .= " # Hydra build ${\$build->id}\n"; + my $attr = $build->get_column('job'); + $attr =~ s/\./-/g; + $res .= " ${\escape $attr} = (mkFakeDerivation {\n"; + $res .= " type = \"derivation\";\n"; + $res .= " name = ${\escape ($build->get_column('releasename') or $build->nixname)};\n"; + $res .= " system = ${\escape $build->system};\n"; + $res .= " meta = {\n"; + $res .= " description = ${\escape $build->description};\n" + if $build->description; + $res .= " longDescription = ${\escape $build->longdescription};\n" + if $build->longdescription; + $res .= " license = ${\escape $build->license};\n" + if $build->license; + $res .= " maintainers = ${\escape $build->maintainers};\n" + if $build->maintainers; + $res .= " };\n"; + $res .= " } {\n"; + my @outputNames = sort (keys $pkg->{outputs}); + $res .= " ${\escape $_} = ${\escape $pkg->{outputs}->{$_}};\n" foreach @outputNames; + my $out = defined $pkg->{outputs}->{"out"} ? "out" : $outputNames[0]; + $res .= " }).$out;\n\n"; + } + $res .= "}\n\n"; $first = 0; } diff --git a/src/root/channel-contents.tt b/src/root/channel-contents.tt index ad040d67..b5f3d269 100644 --- a/src/root/channel-contents.tt +++ b/src/root/channel-contents.tt @@ -60,7 +60,6 @@ install the package simply by clicking on the packages below.

[% ELSE %] [% HTML.escape(b.description) %] [% END %] - [% IF pkg.outName != 'out' %] [[% pkg.outName %]][% END %]