LBNVQXUBEZ45SOTGVXK5UEZXIAIZTJLWZNUYFI4JZ6J65N3KPDVQC
SMM4HQTPAY45254O7GQOJVLHP5LZ6BXDKGNE7IKUJHB5XKH244ZAC
PKPWUHUXLGPQFQUTNHLVGWNT6AB3H2VMDCBKT6IPZDC53CEL4W7QC
SHBLLAVHMMHOPCJ5NPGDZQPVRAMPMGXSFEMX7H7BETW6GTRGUUBAC
J5UVLXOK6EDIL5I7VKWH4V2QDS4DPD7FHRK6XBWSXFRQS4JKXFZQC
HK32XC42XOS7JKJMFT3XJKPXVSI44SFGKUUSJIL5VGPIHYNNWXLAC
PBFZEQLZXMOBQIWL5WQWH7D62XG6M7ROEEAH6PWAKKKOM3W5I3RQC
UAPS46BQNEZACYO2LYXEXIK5YESDG2N2B3BYIZGVETGP6LOM4OGAC
GCHNNFZPCYM3BPOCU5GASALJ6ONWMEVEEGVD7KKLTWC7YQKJ5KZAC
FHF6IZJQPUQHY5QWQYRPZVDBRLHREWRHGNKVQDT7F3GQKKLZXJKQC
W6DC6K4INJQOJYR553ISCKZV7YIOGHEM3FZQPOLAPSZQ3KSJDMRQC
JLDUSNUOOQNL63BOPXIWZOWFRQ5X35RWG33PJB3J3KMR6QR7TN7QC
JD27RBKM7ROBUKBEQDFSCPO3MDE2AFZ6DSSKFUPJ7IC2MCGDVFGAC
ELCI5T2ALF37VXYM5POHPO3CAMMPRB65BXGDRVUAZG53NKKLGIEAC
WHAFVCEIHCWHKY2UVRGRQORERUAK6SZJI7ZENA367ZX4EXDIQMDQC
LQNBKF3DKVYK3NPDGK7OLOTIWIF4HR3EKLRYNLZJB4G3NMIVBCEAC
WZ3AEJ67LOG5L335AAC2BDLIJPIU4VSCGBMATBHDZC26ECRS5A6AC
BD3GRK4BQUGRQGTAILUITIH3RRSVUH6AKINVMMKYLBAAHAAUSB4AC
IW6XNRL7KVUUXV7JH2AEVKNPSJ4KOXCGRK7J7BS744L74TGLFORQC
CLJQCY2XHIDNNMFBJ5PK3GQEN6RFALEFKXBJRWZPEIKR4PR5ZQ5AC
AS5PAYLIRJWB4JGU6N7WKILONGDIGCKNKS4ZSLRYCNGMUAP3AQSAC
BA46C5LNEQ57N52IJTCEXW4J74F33KKNYHYXE6ZJLQ5ARMCJPUHAC
L5VIEXSC5R72SEDSWF7HWNXMSTAAADBUMCSREU5ITMRXLEJ6KZWQC
MOCEUXZAS4CNZL2QDKGVTZCRZ6AMOO2WSFHJ4VPZPPPAXHANG4NAC
KOTB7BKVML6T6S5ZNTQ6456FMGCRZCP3E3KVWCOW7T6SPRHC53LAC
IK53RV4VGOHLCZGQCCIKPB45M3C7M7YMNBOJFBGZJ4LWIZNU4QNQC
L7LFU6IQA7XLRG67U34INTUSYIWP66LFFJE43J6S3GMMQHXXFKRAC
JFZNAYJXKCMXYHGCLTRH7Q6TOFGJ4BT6332GONCWVYRLNMDDG3KAC
Y35C6GHH45ZUEZHHYZU4BQK3GOPJENOY2DZM3TMVUA6AMSPT2I7AC
package Hydra::Controller::Build;
use strict;
use warnings;
use parent 'Catalyst::Controller';
use Hydra::Helper::Nix;
use Hydra::Helper::CatalystUtils;
# Security checking of filenames.
my $pathCompRE = "(?:[A-Za-z0-9-\+][A-Za-z0-9-\+\._]*)";
my $relPathRE = "(?:$pathCompRE(?:\/$pathCompRE)*)";
sub build : Chained('/') PathPart CaptureArgs(1) {
my ($self, $c, $id) = @_;
$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;
}
$c->stash->{curProject} = $c->stash->{build}->project;
}
sub view_build : Chained('build') PathPart('') Args(0) {
my ($self, $c) = @_;
my $build = $c->stash->{build};
$c->stash->{template} = 'build.tt';
$c->stash->{curTime} = time;
$c->stash->{available} = isValidPath $build->outpath;
if (!$build->finished && $build->schedulingInfo->busy) {
my $logfile = $build->schedulingInfo->logfile;
$c->stash->{logtext} = `cat $logfile`;
}
}
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;
$c->stash->{template} = 'log.tt';
$c->stash->{step} = $step;
# !!! should be done in the view (as a TT plugin).
$c->stash->{logtext} = loadLog($c, $step->logfile);
}
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;
$c->stash->{template} = 'log.tt';
# !!! should be done in the view (as a TT plugin).
$c->stash->{logtext} = loadLog($c, $c->stash->{build}->resultInfo->logfile);
}
sub loadLog {
my ($c, $path) = @_;
die unless defined $path;
# !!! quick hack
my $pipeline = ($path =~ /.bz2$/ ? "cat $path | bzip2 -d" : "cat $path")
. " | nix-log2xml | xsltproc " . $c->path_to("xsl/mark-errors.xsl") . " -"
. " | xsltproc " . $c->path_to("xsl/log2html.xsl") . " - | tail -n +2";
return `$pipeline`;
}
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;
return 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$/;
}
my $path = $product->path;
$path .= "/" . join("/", @path) if scalar @path > 0;
# If this is a directory but no "/" is attached, then redirect.
if (-d $path && substr($c->request->uri, -1) ne "/") {
return $c->res->redirect($c->request->uri . "/");
}
$path = "$path/index.html" if -d $path && -e "$path/index.html";
if (!-e $path) {
return error($c, "File $path does not exist.");
}
$c->serve_static_file($path);
}
1;
}
sub getBuild {
my ($c, $id) = @_;
my $build = $c->model('DB::Builds')->find($id);
return $build;
}
sub build : Chained('/') PathPart CaptureArgs(1) {
my ($self, $c, $id) = @_;
$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;
}
$c->stash->{curProject} = $c->stash->{build}->project;
}
sub view_build : Chained('build') PathPart('') Args(0) {
my ($self, $c) = @_;
my $build = $c->stash->{build};
$c->stash->{template} = 'build.tt';
$c->stash->{curTime} = time;
$c->stash->{available} = isValidPath $build->outpath;
if (!$build->finished && $build->schedulingInfo->busy) {
my $logfile = $build->schedulingInfo->logfile;
$c->stash->{logtext} = `cat $logfile`;
}
}
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;
$c->stash->{template} = 'log.tt';
$c->stash->{step} = $step;
# !!! should be done in the view (as a TT plugin).
$c->stash->{logtext} = loadLog($c, $step->logfile);
}
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;
$c->stash->{template} = 'log.tt';
# !!! should be done in the view (as a TT plugin).
$c->stash->{logtext} = loadLog($c, $c->stash->{build}->resultInfo->logfile);
}
sub loadLog {
my ($c, $path) = @_;
die unless defined $path;
# !!! quick hack
my $pipeline = ($path =~ /.bz2$/ ? "cat $path | bzip2 -d" : "cat $path")
. " | nix-log2xml | xsltproc " . $c->path_to("xsl/mark-errors.xsl") . " -"
. " | xsltproc " . $c->path_to("xsl/log2html.xsl") . " - | tail -n +2";
return `$pipeline`;
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;
return 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$/;
}
my $path = $product->path;
$path .= "/" . join("/", @path) if scalar @path > 0;
# If this is a directory but no "/" is attached, then redirect.
if (-d $path && substr($c->request->uri, -1) ne "/") {
return $c->res->redirect($c->request->uri . "/");
}
$path = "$path/index.html" if -d $path && -e "$path/index.html";
if (!-e $path) {
return error($c, "File $path does not exist.");
}
$c->serve_static_file($path);
}
package Hydra::Helper::CatalystUtils;
use strict;
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(getBuild error);
sub getBuild {
my ($c, $id) = @_;
my $build = $c->model('DB::Builds')->find($id);
return $build;
}
sub error {
my ($c, $msg) = @_;
$c->error($msg);
$c->detach;
}
1;