forked from lix-project/hydra
* Refactoring.
This commit is contained in:
parent
537f7c8c88
commit
76c3ae1cef
27
src/Hydra/lib/Hydra/Base/Controller/Nix.pm
Normal file
27
src/Hydra/lib/Hydra/Base/Controller/Nix.pm
Normal file
|
@ -0,0 +1,27 @@
|
|||
package Hydra::Base::Controller::Nix;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use parent 'Catalyst::Controller';
|
||||
use Hydra::Helper::Nix;
|
||||
use Hydra::Helper::CatalystUtils;
|
||||
|
||||
|
||||
sub closure : Chained('nix') PathPart {
|
||||
my ($self, $c) = @_;
|
||||
$c->stash->{current_view} = 'Hydra::View::NixClosure';
|
||||
|
||||
# !!! 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');
|
||||
}
|
||||
|
||||
|
||||
sub manifest : Chained('nix') PathPart Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
$c->stash->{current_view} = 'Hydra::View::NixManifest';
|
||||
}
|
||||
|
||||
|
||||
1;
|
|
@ -2,7 +2,7 @@ package Hydra::Controller::Build;
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use parent 'Catalyst::Controller';
|
||||
use base 'Hydra::Base::Controller::Nix';
|
||||
use Hydra::Helper::Nix;
|
||||
use Hydra::Helper::CatalystUtils;
|
||||
|
||||
|
@ -19,11 +19,8 @@ sub build : Chained('/') PathPart CaptureArgs(1) {
|
|||
|
||||
$c->stash->{build} = getBuild($c, $id);
|
||||
|
||||
if (!defined $c->stash->{build}) {
|
||||
error($c, "Build with ID $id doesn't exist.");
|
||||
$c->response->status(404);
|
||||
return;
|
||||
}
|
||||
notFound($c, "Build with ID $id doesn't exist.")
|
||||
if !defined $c->stash->{build};
|
||||
|
||||
$c->stash->{curProject} = $c->stash->{build}->project;
|
||||
}
|
||||
|
@ -49,7 +46,7 @@ sub view_nixlog : Chained('build') PathPart('nixlog') Args(1) {
|
|||
my ($self, $c, $stepnr) = @_;
|
||||
|
||||
my $step = $c->stash->{build}->buildsteps->find({stepnr => $stepnr});
|
||||
return error($c, "Build doesn't have a build step $stepnr.") if !defined $step;
|
||||
notFound($c, "Build doesn't have a build step $stepnr.") if !defined $step;
|
||||
|
||||
$c->stash->{template} = 'log.tt';
|
||||
$c->stash->{step} = $step;
|
||||
|
@ -62,7 +59,7 @@ sub view_nixlog : Chained('build') PathPart('nixlog') Args(1) {
|
|||
sub view_log : Chained('build') PathPart('log') Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
return error($c, "Build didn't produce a log.") if !defined $c->stash->{build}->resultInfo->logfile;
|
||||
error($c, "Build didn't produce a log.") if !defined $c->stash->{build}->resultInfo->logfile;
|
||||
|
||||
$c->stash->{template} = 'log.tt';
|
||||
|
||||
|
@ -89,13 +86,13 @@ sub download : Chained('build') PathPart('download') {
|
|||
my ($self, $c, $productnr, $filename, @path) = @_;
|
||||
|
||||
my $product = $c->stash->{build}->buildproducts->find({productnr => $productnr});
|
||||
return error($c, "Build doesn't have a product $productnr.") if !defined $product;
|
||||
notFound($c, "Build doesn't have a product $productnr.") if !defined $product;
|
||||
|
||||
return error($c, "Product " . $product->path . " has disappeared.") unless -e $product->path;
|
||||
error($c, "Product " . $product->path . " has disappeared.") unless -e $product->path;
|
||||
|
||||
# Security paranoia.
|
||||
foreach my $elem (@path) {
|
||||
return error($c, "Invalid filename $elem.") if $elem !~ /^$pathCompRE$/;
|
||||
error($c, "Invalid filename $elem.") if $elem !~ /^$pathCompRE$/;
|
||||
}
|
||||
|
||||
my $path = $product->path;
|
||||
|
@ -108,12 +105,26 @@ sub download : Chained('build') PathPart('download') {
|
|||
|
||||
$path = "$path/index.html" if -d $path && -e "$path/index.html";
|
||||
|
||||
if (!-e $path) {
|
||||
return error($c, "File $path does not exist.");
|
||||
}
|
||||
notFound($c, "File $path does not exist.") if !-e $path;
|
||||
|
||||
$c->serve_static_file($path);
|
||||
}
|
||||
|
||||
|
||||
sub nix : Chained('build') PathPart('nix') CaptureArgs(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $build = $c->stash->{build};
|
||||
|
||||
error($c, "Build cannot be downloaded as a closure or Nix package.")
|
||||
if !$build->buildproducts->find({type => "nix-build"});
|
||||
|
||||
error($c, "Path " . $build->outpath . " is no longer available.")
|
||||
unless isValidPath($build->outpath);
|
||||
|
||||
$c->stash->{name} = $build->nixname;
|
||||
$c->stash->{storePaths} = [$build->outpath];
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
|
|
@ -2,7 +2,7 @@ package Hydra::Controller::Root;
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use parent 'Catalyst::Controller';
|
||||
use base 'Catalyst::Controller';
|
||||
use Hydra::Helper::Nix;
|
||||
use Hydra::Helper::CatalystUtils;
|
||||
|
||||
|
@ -152,7 +152,7 @@ sub releasesets :Local {
|
|||
$c->stash->{template} = 'releasesets.tt';
|
||||
|
||||
my $project = $c->model('DB::Projects')->find($projectName);
|
||||
return error($c, "Project $projectName doesn't exist.") if !defined $project;
|
||||
notFound($c, "Project $projectName doesn't exist.") if !defined $project;
|
||||
$c->stash->{curProject} = $project;
|
||||
|
||||
$c->stash->{releaseSets} = [$project->releasesets->all];
|
||||
|
@ -225,7 +225,7 @@ sub releases :Local {
|
|||
|
||||
return requireLogin($c) if !$c->user_exists;
|
||||
|
||||
return error($c, "Only the project owner or the administrator can perform this operation.")
|
||||
error($c, "Only the project owner or the administrator can perform this operation.")
|
||||
unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
|
||||
|
||||
if ($subcommand eq "edit") {
|
||||
|
@ -247,7 +247,7 @@ sub releases :Local {
|
|||
return $c->res->redirect($c->uri_for("/releasesets", $projectName));
|
||||
}
|
||||
|
||||
else { return error($c, "Unknown subcommand."); }
|
||||
else { error($c, "Unknown subcommand."); }
|
||||
}
|
||||
|
||||
$c->stash->{template} = 'releases.tt';
|
||||
|
@ -267,11 +267,10 @@ sub create_releaseset :Local {
|
|||
|
||||
return requireLogin($c) if !$c->user_exists;
|
||||
|
||||
return error($c, "Only the project owner or the administrator can perform this operation.")
|
||||
error($c, "Only the project owner or the administrator can perform this operation.")
|
||||
unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
|
||||
|
||||
if (defined $subcommand && $subcommand eq "submit") {
|
||||
eval {
|
||||
my $releaseSetName = $c->request->params->{name};
|
||||
$c->model('DB')->schema->txn_do(sub {
|
||||
# Note: $releaseSetName is validated in updateProject,
|
||||
|
@ -281,10 +280,6 @@ sub create_releaseset :Local {
|
|||
updateReleaseSet($c, $releaseSet);
|
||||
return $c->res->redirect($c->uri_for("/releases", $projectName, $releaseSet->name));
|
||||
});
|
||||
};
|
||||
if ($@) {
|
||||
return error($c, $@);
|
||||
}
|
||||
}
|
||||
|
||||
$c->stash->{template} = 'edit-releaseset.tt';
|
||||
|
@ -301,7 +296,7 @@ sub release :Local {
|
|||
if ($releaseId eq "latest") {
|
||||
# Redirect to the latest successful release.
|
||||
my $latest = getLatestSuccessfulRelease($project, $primaryJob, $jobs);
|
||||
return error($c, "This release set has no successful releases yet.") if !defined $latest;
|
||||
error($c, "This release set has no successful releases yet.") if !defined $latest;
|
||||
return $c->res->redirect($c->uri_for("/release", $projectName, $releaseSetName, $latest->id));
|
||||
}
|
||||
|
||||
|
@ -309,7 +304,7 @@ sub release :Local {
|
|||
# build, but who cares?
|
||||
my $primaryBuild = $project->builds->find($releaseId,
|
||||
{ join => 'resultInfo', '+select' => ["resultInfo.releasename"], '+as' => ["releasename"] });
|
||||
return error($c, "Release $releaseId doesn't exist.") if !defined $primaryBuild;
|
||||
error($c, "Release $releaseId doesn't exist.") if !defined $primaryBuild;
|
||||
|
||||
$c->stash->{release} = getRelease($primaryBuild, $jobs);
|
||||
}
|
||||
|
@ -447,7 +442,7 @@ sub project :Local {
|
|||
$c->stash->{template} = 'project.tt';
|
||||
|
||||
my $project = $c->model('DB::Projects')->find($projectName);
|
||||
return error($c, "Project $projectName doesn't exist.") if !defined $project;
|
||||
notFound($c, "Project $projectName doesn't exist.") if !defined $project;
|
||||
|
||||
my $isPosted = $c->request->method eq "POST";
|
||||
|
||||
|
@ -468,7 +463,7 @@ sub project :Local {
|
|||
|
||||
return requireLogin($c) if !$c->user_exists;
|
||||
|
||||
return error($c, "Only the project owner or the administrator can perform this operation.")
|
||||
error($c, "Only the project owner or the administrator can perform this operation.")
|
||||
unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
|
||||
|
||||
if ($subcommand eq "edit") {
|
||||
|
@ -490,7 +485,7 @@ sub project :Local {
|
|||
}
|
||||
|
||||
else {
|
||||
return error($c, "Unknown subcommand $subcommand.");
|
||||
error($c, "Unknown subcommand $subcommand.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,11 +501,10 @@ sub createproject :Local {
|
|||
|
||||
return requireLogin($c) if !$c->user_exists;
|
||||
|
||||
return error($c, "Only administrators can create projects.")
|
||||
error($c, "Only administrators can create projects.")
|
||||
unless $c->check_user_roles('admin');
|
||||
|
||||
if (defined $subcommand && $subcommand eq "submit") {
|
||||
eval {
|
||||
my $projectName = trim $c->request->params->{name};
|
||||
$c->model('DB')->schema->txn_do(sub {
|
||||
# Note: $projectName is validated in updateProject,
|
||||
|
@ -521,10 +515,6 @@ sub createproject :Local {
|
|||
updateProject($c, $project);
|
||||
});
|
||||
return $c->res->redirect($c->uri_for("/project", $projectName));
|
||||
};
|
||||
if ($@) {
|
||||
return error($c, $@);
|
||||
}
|
||||
}
|
||||
|
||||
$c->stash->{template} = 'project.tt';
|
||||
|
@ -538,7 +528,7 @@ sub job :Local {
|
|||
$c->stash->{template} = 'job.tt';
|
||||
|
||||
my $project = $c->model('DB::Projects')->find($projectName);
|
||||
return error($c, "Project $projectName doesn't exist.") if !defined $project;
|
||||
notFound($c, "Project $projectName doesn't exist.") if !defined $project;
|
||||
$c->stash->{curProject} = $project;
|
||||
|
||||
$c->stash->{jobName} = $jobName;
|
||||
|
@ -550,44 +540,7 @@ sub job :Local {
|
|||
|
||||
sub default :Path {
|
||||
my ($self, $c) = @_;
|
||||
error($c, "Page not found.");
|
||||
$c->response->status(404);
|
||||
}
|
||||
|
||||
|
||||
sub closure :Local {
|
||||
my ($self, $c, $buildId) = @_;
|
||||
|
||||
my $build = getBuild($c, $buildId);
|
||||
return error($c, "Build $buildId doesn't exist.") if !defined $build;
|
||||
|
||||
return error($c, "Build $buildId cannot be downloaded as a closure.")
|
||||
if !$build->buildproducts->find({type => "nix-build"});
|
||||
|
||||
return error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
|
||||
|
||||
$c->stash->{current_view} = 'Hydra::View::NixClosure';
|
||||
$c->stash->{storePath} = $build->outpath;
|
||||
$c->stash->{name} = $build->nixname;
|
||||
|
||||
# !!! 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');
|
||||
$c->response->header('Content-Disposition' => 'attachment; filename=' . $c->stash->{name} . '.closure.gz');
|
||||
}
|
||||
|
||||
|
||||
sub manifest :Local {
|
||||
my ($self, $c, $buildId) = @_;
|
||||
|
||||
my $build = getBuild($c, $buildId);
|
||||
return error($c, "Build with ID $buildId doesn't exist.") if !defined $build;
|
||||
|
||||
return error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
|
||||
|
||||
$c->stash->{current_view} = 'Hydra::View::NixManifest';
|
||||
$c->stash->{storePath} = $build->outpath;
|
||||
notFound($c, "Page not found.");
|
||||
}
|
||||
|
||||
|
||||
|
@ -595,12 +548,12 @@ sub nixpkg :Local {
|
|||
my ($self, $c, $buildId) = @_;
|
||||
|
||||
my $build = getBuild($c, $buildId);
|
||||
return error($c, "Build $buildId doesn't exist.") if !defined $build;
|
||||
notFound($c, "Build $buildId doesn't exist.") if !defined $build;
|
||||
|
||||
return error($c, "Build $buildId cannot be downloaded as a Nix package.")
|
||||
error($c, "Build $buildId cannot be downloaded as a Nix package.")
|
||||
if !$build->buildproducts->find({type => "nix-build"});
|
||||
|
||||
return error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
|
||||
error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
|
||||
|
||||
$c->stash->{current_view} = 'Hydra::View::NixPkg';
|
||||
$c->stash->{build} = $build;
|
||||
|
@ -614,7 +567,7 @@ sub nar :Local {
|
|||
|
||||
my $path .= "/" . join("/", @rest);
|
||||
|
||||
return error($c, "Path " . $path . " is no longer available.") unless isValidPath($path);
|
||||
error($c, "Path " . $path . " is no longer available.") unless isValidPath($path);
|
||||
|
||||
$c->stash->{current_view} = 'Hydra::View::NixNAR';
|
||||
$c->stash->{storePath} = $path;
|
||||
|
|
|
@ -4,7 +4,7 @@ use strict;
|
|||
use Exporter;
|
||||
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(getBuild error);
|
||||
our @EXPORT = qw(getBuild error notFound);
|
||||
|
||||
|
||||
sub getBuild {
|
||||
|
@ -21,4 +21,11 @@ sub error {
|
|||
}
|
||||
|
||||
|
||||
sub notFound {
|
||||
my ($c, $msg) = @_;
|
||||
$c->response->status(404);
|
||||
error($c, $msg);
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
|
|
@ -5,14 +5,13 @@ use base qw/Catalyst::View/;
|
|||
use IO::Pipe;
|
||||
|
||||
sub process {
|
||||
my ( $self, $c ) = @_;
|
||||
my ($self, $c) = @_;
|
||||
|
||||
$c->response->content_type('application/x-nix-export');
|
||||
$c->response->header('Content-Disposition' => 'attachment; filename=' . $c->stash->{name} . '.closure.gz');
|
||||
|
||||
my $storePath = $c->stash->{storePath};
|
||||
my @storePaths = @{$c->stash->{storePaths}};
|
||||
|
||||
open(OUTPUT, "nix-store --export `nix-store -qR $storePath` | gzip |");
|
||||
open(OUTPUT, "nix-store --export `nix-store -qR @storePaths` | gzip |");
|
||||
|
||||
my $fh = new IO::Handle;
|
||||
$fh->fdopen(fileno(OUTPUT), "r") or die;
|
||||
|
|
|
@ -16,12 +16,12 @@ sub captureStdoutStderr {
|
|||
sub process {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $storePath = $c->stash->{storePath};
|
||||
my @storePaths = @{$c->stash->{storePaths}};
|
||||
|
||||
$c->response->content_type('text/x-nix-manifest');
|
||||
|
||||
my @paths = split '\n', `nix-store --query --requisites $storePath`
|
||||
or die "cannot query dependencies of `$storePath': $?";
|
||||
my @paths = split '\n', `nix-store --query --requisites @storePaths`
|
||||
or die "cannot query dependencies of path(s) @storePaths: $?";
|
||||
|
||||
my $manifest =
|
||||
"version {\n" .
|
||||
|
|
|
@ -43,7 +43,10 @@
|
|||
|
||||
<li class="product">
|
||||
|
||||
<a href="[% c.uri_for('/closure' build.id) %]">
|
||||
[% filename = "${build.nixname}.closure.gz" %]
|
||||
[% uri = c.uri_for('/build' build.id 'nix' 'closure' filename ) %]
|
||||
|
||||
<a href="[% uri %]">
|
||||
<img src="/static/images/nix-build.png" alt="Source" />
|
||||
Nix closure of path <tt>[% product.path %]</tt>
|
||||
</a>
|
||||
|
@ -54,11 +57,11 @@
|
|||
all its dependencies can be unpacked into your local Nix
|
||||
store by doing:</p>
|
||||
|
||||
<pre>$ gunzip < [% HTML.escape(build.nixname) %].closure.gz | nix-store --import</pre>
|
||||
<pre>$ gunzip < [% filename %] | nix-store --import</pre>
|
||||
|
||||
or to download and unpack in one command:
|
||||
|
||||
<pre>$ curl [% c.uri_for('/closure' build.id) %] | gunzip | nix-store --import</pre>
|
||||
<pre>$ curl [% uri %] | gunzip | nix-store --import</pre>
|
||||
|
||||
<p>The package can then be found in the path <tt>[%
|
||||
product.path %]</tt>. You’ll probably also want to do
|
||||
|
|
Loading…
Reference in a new issue