2009-03-04 12:23:54 +00:00
|
|
|
package Hydra::Base::Controller::NixChannel;
|
2009-02-25 14:34:29 +00:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
2013-06-17 12:34:21 -04:00
|
|
|
use base 'Hydra::Base::Controller::REST';
|
2013-02-13 16:49:28 +00:00
|
|
|
use List::MoreUtils qw(all);
|
2012-03-08 01:17:59 +01:00
|
|
|
use Nix::Store;
|
2009-02-25 14:34:29 +00:00
|
|
|
use Hydra::Helper::Nix;
|
|
|
|
use Hydra::Helper::CatalystUtils;
|
|
|
|
|
|
|
|
|
2012-03-08 01:17:59 +01:00
|
|
|
sub getChannelData {
|
|
|
|
my ($c, $checkValidity) = @_;
|
|
|
|
|
|
|
|
my @storePaths = ();
|
2013-02-13 16:49:28 +00:00
|
|
|
$c->stash->{nixPkgs} = [];
|
2013-10-07 17:06:17 +02:00
|
|
|
|
|
|
|
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 };
|
|
|
|
}
|
2012-03-08 01:17:59 +01:00
|
|
|
|
|
|
|
$c->stash->{storePaths} = [@storePaths];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-25 14:34:29 +00:00
|
|
|
sub closure : Chained('nix') PathPart {
|
|
|
|
my ($self, $c) = @_;
|
2010-06-22 12:00:19 +00:00
|
|
|
$c->stash->{current_view} = 'NixClosure';
|
2009-02-25 14:34:29 +00:00
|
|
|
|
2012-03-08 01:17:59 +01:00
|
|
|
getChannelData($c, 1);
|
|
|
|
|
2013-02-13 16:49:28 +00:00
|
|
|
# FIXME: get the closure of the selected path only.
|
|
|
|
|
2009-02-25 14:34:29 +00:00
|
|
|
# !!! quick hack; this is to make HEAD requests return the right
|
|
|
|
# MIME type. This is set in the view as well, but the view isn't
|
|
|
|
# called for HEAD requests. There should be a cleaner solution...
|
|
|
|
$c->response->content_type('application/x-nix-export');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-03 14:21:27 +00:00
|
|
|
sub manifest : Chained('nix') PathPart("MANIFEST") Args(0) {
|
2009-02-25 14:34:29 +00:00
|
|
|
my ($self, $c) = @_;
|
2010-06-22 12:00:19 +00:00
|
|
|
$c->stash->{current_view} = 'NixManifest';
|
|
|
|
$c->stash->{narBase} = $c->uri_for($c->controller('Root')->action_for("nar"));
|
2012-03-08 01:17:59 +01:00
|
|
|
getChannelData($c, 1);
|
2009-02-25 14:34:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-25 15:39:51 +00:00
|
|
|
sub pkg : Chained('nix') PathPart Args(1) {
|
|
|
|
my ($self, $c, $pkgName) = @_;
|
|
|
|
|
2012-03-08 01:17:59 +01:00
|
|
|
if (!$c->stash->{build}) {
|
|
|
|
$pkgName =~ /-(\d+)\.nixpkg$/ or notFound($c, "Bad package name.");
|
2013-02-13 16:49:28 +00:00
|
|
|
# FIXME: need to handle multiple outputs: channelBuilds is
|
|
|
|
# joined with the build outputs, so find() can return multiple
|
|
|
|
# results.
|
2012-03-08 01:17:59 +01:00
|
|
|
$c->stash->{build} = $c->stash->{channelBuilds}->find({ id => $1 })
|
|
|
|
|| notFound($c, "No such package in this channel.");
|
|
|
|
}
|
2009-02-25 15:39:51 +00:00
|
|
|
|
2013-02-13 16:49:28 +00:00
|
|
|
unless (all { isValidPath($_->path) } $c->stash->{build}->buildoutputs->all) {
|
2012-03-08 01:17:59 +01:00
|
|
|
$c->response->status(410); # "Gone"
|
|
|
|
error($c, "Build " . $c->stash->{build}->id . " is no longer available.");
|
|
|
|
}
|
2009-02-25 15:39:51 +00:00
|
|
|
|
2009-02-26 21:33:29 +00:00
|
|
|
$c->stash->{manifestUri} = $c->uri_for($self->action_for("manifest"), $c->req->captures);
|
|
|
|
|
2010-06-22 12:00:19 +00:00
|
|
|
$c->stash->{current_view} = 'NixPkg';
|
2009-02-25 15:39:51 +00:00
|
|
|
|
|
|
|
$c->response->content_type('application/nix-package');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-03 10:44:54 +00:00
|
|
|
sub nixexprs : Chained('nix') PathPart('nixexprs.tar.bz2') Args(0) {
|
2009-03-02 17:17:36 +00:00
|
|
|
my ($self, $c) = @_;
|
2010-06-22 12:00:19 +00:00
|
|
|
$c->stash->{current_view} = 'NixExprs';
|
2012-03-08 01:17:59 +01:00
|
|
|
getChannelData($c, 1);
|
2009-03-02 17:17:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-01 16:31:25 +00:00
|
|
|
sub binary_cache_url : Chained('nix') PathPart('binary-cache-url') Args(0) {
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
$c->stash->{'plain'} = { data => $c->uri_for('/') };
|
2012-08-01 18:00:55 +00:00
|
|
|
$c->response->content_type('text/plain');
|
2012-08-01 16:31:25 +00:00
|
|
|
$c->forward('Hydra::View::Plain');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-04 14:49:21 +00:00
|
|
|
sub name {
|
|
|
|
my ($build) = @_;
|
2012-03-07 22:20:15 +01:00
|
|
|
return $build->releasename || $build->nixname;
|
2009-03-04 14:49:21 +00:00
|
|
|
}
|
|
|
|
|
2009-03-04 15:47:42 +00:00
|
|
|
|
|
|
|
sub sortPkgs {
|
2012-03-07 22:20:15 +01:00
|
|
|
# Sort by name, then id.
|
2009-03-04 15:47:42 +00:00
|
|
|
return sort
|
|
|
|
{ lc(name($a->{build})) cmp lc(name($b->{build}))
|
2012-03-07 22:20:15 +01:00
|
|
|
or $a->{build}->id <=> $b->{build}->id } @_;
|
2009-03-04 15:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-04 14:49:21 +00:00
|
|
|
sub channel_contents : Chained('nix') PathPart('') Args(0) {
|
|
|
|
my ($self, $c) = @_;
|
2012-03-08 01:17:59 +01:00
|
|
|
# Optimistically assume that none of the packages have been
|
|
|
|
# garbage-collected. That should be true for the "latest"
|
|
|
|
# channel.
|
|
|
|
getChannelData($c, 0);
|
2009-03-04 14:49:21 +00:00
|
|
|
$c->stash->{template} = 'channel-contents.tt';
|
2013-02-13 16:49:28 +00:00
|
|
|
$c->stash->{nixPkgs} = [sortPkgs @{$c->stash->{nixPkgs}}];
|
2009-03-04 14:49:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-25 14:34:29 +00:00
|
|
|
1;
|