From 76c3ae1cef2f8030a160282cb39e17f1ea1af171 Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Wed, 25 Feb 2009 14:34:29 +0000
Subject: [PATCH] * Refactoring.
---
src/Hydra/lib/Hydra/Base/Controller/Nix.pm | 27 +++++
src/Hydra/lib/Hydra/Controller/Build.pm | 41 ++++---
src/Hydra/lib/Hydra/Controller/Root.pm | 119 ++++++--------------
src/Hydra/lib/Hydra/Helper/CatalystUtils.pm | 9 +-
src/Hydra/lib/Hydra/View/NixClosure.pm | 7 +-
src/Hydra/lib/Hydra/View/NixManifest.pm | 6 +-
src/Hydra/root/product-list.tt | 9 +-
7 files changed, 109 insertions(+), 109 deletions(-)
create mode 100644 src/Hydra/lib/Hydra/Base/Controller/Nix.pm
diff --git a/src/Hydra/lib/Hydra/Base/Controller/Nix.pm b/src/Hydra/lib/Hydra/Base/Controller/Nix.pm
new file mode 100644
index 00000000..9355f1cc
--- /dev/null
+++ b/src/Hydra/lib/Hydra/Base/Controller/Nix.pm
@@ -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;
diff --git a/src/Hydra/lib/Hydra/Controller/Build.pm b/src/Hydra/lib/Hydra/Controller/Build.pm
index ae8077b6..a5d21b3f 100644
--- a/src/Hydra/lib/Hydra/Controller/Build.pm
+++ b/src/Hydra/lib/Hydra/Controller/Build.pm
@@ -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;
@@ -18,12 +18,9 @@ sub build : Chained('/') PathPart CaptureArgs(1) {
$c->stash->{id} = $id;
$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;
diff --git a/src/Hydra/lib/Hydra/Controller/Root.pm b/src/Hydra/lib/Hydra/Controller/Root.pm
index 3ad52585..f46c4a17 100644
--- a/src/Hydra/lib/Hydra/Controller/Root.pm
+++ b/src/Hydra/lib/Hydra/Controller/Root.pm
@@ -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,24 +267,19 @@ 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,
- # which will abort the transaction if the name isn't
- # valid.
- my $releaseSet = $project->releasesets->create({name => $releaseSetName});
- updateReleaseSet($c, $releaseSet);
- return $c->res->redirect($c->uri_for("/releases", $projectName, $releaseSet->name));
- });
- };
- if ($@) {
- return error($c, $@);
- }
+ my $releaseSetName = $c->request->params->{name};
+ $c->model('DB')->schema->txn_do(sub {
+ # Note: $releaseSetName is validated in updateProject,
+ # which will abort the transaction if the name isn't
+ # valid.
+ my $releaseSet = $project->releasesets->create({name => $releaseSetName});
+ updateReleaseSet($c, $releaseSet);
+ return $c->res->redirect($c->uri_for("/releases", $projectName, $releaseSet->name));
+ });
}
$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,25 +501,20 @@ 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,
- # which will abort the transaction if the name isn't
- # valid. Idem for the owner.
- my $project = $c->model('DB::Projects')->create(
- {name => $projectName, displayname => "", owner => trim $c->request->params->{owner}});
- updateProject($c, $project);
- });
- return $c->res->redirect($c->uri_for("/project", $projectName));
- };
- if ($@) {
- return error($c, $@);
- }
+ my $projectName = trim $c->request->params->{name};
+ $c->model('DB')->schema->txn_do(sub {
+ # Note: $projectName is validated in updateProject,
+ # which will abort the transaction if the name isn't
+ # valid. Idem for the owner.
+ my $project = $c->model('DB::Projects')->create(
+ {name => $projectName, displayname => "", owner => trim $c->request->params->{owner}});
+ updateProject($c, $project);
+ });
+ return $c->res->redirect($c->uri_for("/project", $projectName));
}
$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;
diff --git a/src/Hydra/lib/Hydra/Helper/CatalystUtils.pm b/src/Hydra/lib/Hydra/Helper/CatalystUtils.pm
index 9fc71389..66577520 100644
--- a/src/Hydra/lib/Hydra/Helper/CatalystUtils.pm
+++ b/src/Hydra/lib/Hydra/Helper/CatalystUtils.pm
@@ -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;
diff --git a/src/Hydra/lib/Hydra/View/NixClosure.pm b/src/Hydra/lib/Hydra/View/NixClosure.pm
index 3d69d7ee..ec820b6d 100644
--- a/src/Hydra/lib/Hydra/View/NixClosure.pm
+++ b/src/Hydra/lib/Hydra/View/NixClosure.pm
@@ -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;
diff --git a/src/Hydra/lib/Hydra/View/NixManifest.pm b/src/Hydra/lib/Hydra/View/NixManifest.pm
index 2d9b555a..cb45c197 100644
--- a/src/Hydra/lib/Hydra/View/NixManifest.pm
+++ b/src/Hydra/lib/Hydra/View/NixManifest.pm
@@ -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" .
diff --git a/src/Hydra/root/product-list.tt b/src/Hydra/root/product-list.tt
index 8331c69f..eda24140 100644
--- a/src/Hydra/root/product-list.tt
+++ b/src/Hydra/root/product-list.tt
@@ -43,7 +43,10 @@
-
+ [% filename = "${build.nixname}.closure.gz" %]
+ [% uri = c.uri_for('/build' build.id 'nix' 'closure' filename ) %]
+
+
Nix closure of path [% product.path %]
@@ -54,11 +57,11 @@
all its dependencies can be unpacked into your local Nix
store by doing:
- $ gunzip < [% HTML.escape(build.nixname) %].closure.gz | nix-store --import
+ $ gunzip < [% filename %] | nix-store --import
or to download and unpack in one command:
- $ curl [% c.uri_for('/closure' build.id) %] | gunzip | nix-store --import
+ $ curl [% uri %] | gunzip | nix-store --import
The package can then be found in the path [%
product.path %]. You’ll probably also want to do