* Refactoring.

This commit is contained in:
Eelco Dolstra 2009-02-25 14:34:29 +00:00
parent 537f7c8c88
commit 76c3ae1cef
7 changed files with 109 additions and 109 deletions

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

View file

@ -2,7 +2,7 @@ package Hydra::Controller::Build;
use strict; use strict;
use warnings; use warnings;
use parent 'Catalyst::Controller'; use base 'Hydra::Base::Controller::Nix';
use Hydra::Helper::Nix; use Hydra::Helper::Nix;
use Hydra::Helper::CatalystUtils; use Hydra::Helper::CatalystUtils;
@ -19,11 +19,8 @@ sub build : Chained('/') PathPart CaptureArgs(1) {
$c->stash->{build} = getBuild($c, $id); $c->stash->{build} = getBuild($c, $id);
if (!defined $c->stash->{build}) { notFound($c, "Build with ID $id doesn't exist.")
error($c, "Build with ID $id doesn't exist."); if !defined $c->stash->{build};
$c->response->status(404);
return;
}
$c->stash->{curProject} = $c->stash->{build}->project; $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 ($self, $c, $stepnr) = @_;
my $step = $c->stash->{build}->buildsteps->find({stepnr => $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->{template} = 'log.tt';
$c->stash->{step} = $step; $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) { sub view_log : Chained('build') PathPart('log') Args(0) {
my ($self, $c) = @_; 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'; $c->stash->{template} = 'log.tt';
@ -89,13 +86,13 @@ sub download : Chained('build') PathPart('download') {
my ($self, $c, $productnr, $filename, @path) = @_; my ($self, $c, $productnr, $filename, @path) = @_;
my $product = $c->stash->{build}->buildproducts->find({productnr => $productnr}); 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. # Security paranoia.
foreach my $elem (@path) { 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; 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"; $path = "$path/index.html" if -d $path && -e "$path/index.html";
if (!-e $path) { notFound($c, "File $path does not exist.") if !-e $path;
return error($c, "File $path does not exist.");
}
$c->serve_static_file($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; 1;

View file

@ -2,7 +2,7 @@ package Hydra::Controller::Root;
use strict; use strict;
use warnings; use warnings;
use parent 'Catalyst::Controller'; use base 'Catalyst::Controller';
use Hydra::Helper::Nix; use Hydra::Helper::Nix;
use Hydra::Helper::CatalystUtils; use Hydra::Helper::CatalystUtils;
@ -152,7 +152,7 @@ sub releasesets :Local {
$c->stash->{template} = 'releasesets.tt'; $c->stash->{template} = 'releasesets.tt';
my $project = $c->model('DB::Projects')->find($projectName); 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->{curProject} = $project;
$c->stash->{releaseSets} = [$project->releasesets->all]; $c->stash->{releaseSets} = [$project->releasesets->all];
@ -225,7 +225,7 @@ sub releases :Local {
return requireLogin($c) if !$c->user_exists; 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; unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
if ($subcommand eq "edit") { if ($subcommand eq "edit") {
@ -247,7 +247,7 @@ sub releases :Local {
return $c->res->redirect($c->uri_for("/releasesets", $projectName)); 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'; $c->stash->{template} = 'releases.tt';
@ -267,11 +267,10 @@ sub create_releaseset :Local {
return requireLogin($c) if !$c->user_exists; 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; unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
if (defined $subcommand && $subcommand eq "submit") { if (defined $subcommand && $subcommand eq "submit") {
eval {
my $releaseSetName = $c->request->params->{name}; my $releaseSetName = $c->request->params->{name};
$c->model('DB')->schema->txn_do(sub { $c->model('DB')->schema->txn_do(sub {
# Note: $releaseSetName is validated in updateProject, # Note: $releaseSetName is validated in updateProject,
@ -281,10 +280,6 @@ sub create_releaseset :Local {
updateReleaseSet($c, $releaseSet); updateReleaseSet($c, $releaseSet);
return $c->res->redirect($c->uri_for("/releases", $projectName, $releaseSet->name)); return $c->res->redirect($c->uri_for("/releases", $projectName, $releaseSet->name));
}); });
};
if ($@) {
return error($c, $@);
}
} }
$c->stash->{template} = 'edit-releaseset.tt'; $c->stash->{template} = 'edit-releaseset.tt';
@ -301,7 +296,7 @@ sub release :Local {
if ($releaseId eq "latest") { if ($releaseId eq "latest") {
# Redirect to the latest successful release. # Redirect to the latest successful release.
my $latest = getLatestSuccessfulRelease($project, $primaryJob, $jobs); 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)); return $c->res->redirect($c->uri_for("/release", $projectName, $releaseSetName, $latest->id));
} }
@ -309,7 +304,7 @@ sub release :Local {
# build, but who cares? # build, but who cares?
my $primaryBuild = $project->builds->find($releaseId, my $primaryBuild = $project->builds->find($releaseId,
{ join => 'resultInfo', '+select' => ["resultInfo.releasename"], '+as' => ["releasename"] }); { 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); $c->stash->{release} = getRelease($primaryBuild, $jobs);
} }
@ -447,7 +442,7 @@ sub project :Local {
$c->stash->{template} = 'project.tt'; $c->stash->{template} = 'project.tt';
my $project = $c->model('DB::Projects')->find($projectName); 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"; my $isPosted = $c->request->method eq "POST";
@ -468,7 +463,7 @@ sub project :Local {
return requireLogin($c) if !$c->user_exists; 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; unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
if ($subcommand eq "edit") { if ($subcommand eq "edit") {
@ -490,7 +485,7 @@ sub project :Local {
} }
else { 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 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'); unless $c->check_user_roles('admin');
if (defined $subcommand && $subcommand eq "submit") { if (defined $subcommand && $subcommand eq "submit") {
eval {
my $projectName = trim $c->request->params->{name}; my $projectName = trim $c->request->params->{name};
$c->model('DB')->schema->txn_do(sub { $c->model('DB')->schema->txn_do(sub {
# Note: $projectName is validated in updateProject, # Note: $projectName is validated in updateProject,
@ -521,10 +515,6 @@ sub createproject :Local {
updateProject($c, $project); updateProject($c, $project);
}); });
return $c->res->redirect($c->uri_for("/project", $projectName)); return $c->res->redirect($c->uri_for("/project", $projectName));
};
if ($@) {
return error($c, $@);
}
} }
$c->stash->{template} = 'project.tt'; $c->stash->{template} = 'project.tt';
@ -538,7 +528,7 @@ sub job :Local {
$c->stash->{template} = 'job.tt'; $c->stash->{template} = 'job.tt';
my $project = $c->model('DB::Projects')->find($projectName); 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->{curProject} = $project;
$c->stash->{jobName} = $jobName; $c->stash->{jobName} = $jobName;
@ -550,44 +540,7 @@ sub job :Local {
sub default :Path { sub default :Path {
my ($self, $c) = @_; my ($self, $c) = @_;
error($c, "Page not found."); notFound($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;
} }
@ -595,12 +548,12 @@ sub nixpkg :Local {
my ($self, $c, $buildId) = @_; my ($self, $c, $buildId) = @_;
my $build = getBuild($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"}); 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->{current_view} = 'Hydra::View::NixPkg';
$c->stash->{build} = $build; $c->stash->{build} = $build;
@ -614,7 +567,7 @@ sub nar :Local {
my $path .= "/" . join("/", @rest); 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->{current_view} = 'Hydra::View::NixNAR';
$c->stash->{storePath} = $path; $c->stash->{storePath} = $path;

View file

@ -4,7 +4,7 @@ use strict;
use Exporter; use Exporter;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw(getBuild error); our @EXPORT = qw(getBuild error notFound);
sub getBuild { sub getBuild {
@ -21,4 +21,11 @@ sub error {
} }
sub notFound {
my ($c, $msg) = @_;
$c->response->status(404);
error($c, $msg);
}
1; 1;

View file

@ -5,14 +5,13 @@ use base qw/Catalyst::View/;
use IO::Pipe; use IO::Pipe;
sub process { sub process {
my ( $self, $c ) = @_; my ($self, $c) = @_;
$c->response->content_type('application/x-nix-export'); $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; my $fh = new IO::Handle;
$fh->fdopen(fileno(OUTPUT), "r") or die; $fh->fdopen(fileno(OUTPUT), "r") or die;

View file

@ -16,12 +16,12 @@ sub captureStdoutStderr {
sub process { sub process {
my ($self, $c) = @_; my ($self, $c) = @_;
my $storePath = $c->stash->{storePath}; my @storePaths = @{$c->stash->{storePaths}};
$c->response->content_type('text/x-nix-manifest'); $c->response->content_type('text/x-nix-manifest');
my @paths = split '\n', `nix-store --query --requisites $storePath` my @paths = split '\n', `nix-store --query --requisites @storePaths`
or die "cannot query dependencies of `$storePath': $?"; or die "cannot query dependencies of path(s) @storePaths: $?";
my $manifest = my $manifest =
"version {\n" . "version {\n" .

View file

@ -43,7 +43,10 @@
<li class="product"> <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" /> <img src="/static/images/nix-build.png" alt="Source" />
Nix closure of path <tt>[% product.path %]</tt> Nix closure of path <tt>[% product.path %]</tt>
</a> </a>
@ -54,11 +57,11 @@
all its dependencies can be unpacked into your local Nix all its dependencies can be unpacked into your local Nix
store by doing:</p> store by doing:</p>
<pre>$ gunzip &lt; [% HTML.escape(build.nixname) %].closure.gz | nix-store --import</pre> <pre>$ gunzip &lt; [% filename %] | nix-store --import</pre>
or to download and unpack in one command: 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>[% <p>The package can then be found in the path <tt>[%
product.path %]</tt>. Youll probably also want to do product.path %]</tt>. Youll probably also want to do