2011-07-18 15:03:15 +00:00
package Hydra::Controller::Jobset ;
2009-03-13 15:23:08 +00:00
use strict ;
use warnings ;
use base 'Hydra::Base::Controller::ListBuilds' ;
use Hydra::Helper::Nix ;
use Hydra::Helper::CatalystUtils ;
sub jobset : Chained('/') PathPart('jobset') CaptureArgs(2) {
my ( $ self , $ c , $ projectName , $ jobsetName ) = @ _ ;
my $ project = $ c - > model ( 'DB::Projects' ) - > find ( $ projectName )
or notFound ( $ c , "Project $projectName doesn't exist." ) ;
2009-03-13 15:41:19 +00:00
$ c - > stash - > { project } = $ project ;
2011-05-16 08:03:06 +00:00
2009-04-08 22:08:00 +00:00
$ c - > stash - > { jobset_ } = $ project - > jobsets - > search ( { name = > $ jobsetName } ) ;
$ c - > stash - > { jobset } = $ c - > stash - > { jobset_ } - > single
2009-03-13 15:23:08 +00:00
or notFound ( $ c , "Jobset $jobsetName doesn't exist." ) ;
}
2012-02-21 17:59:36 +01:00
2010-02-09 13:43:53 +00:00
sub jobsetIndex {
my ( $ self , $ c , $ forceStatus ) = @ _ ;
2009-03-13 15:23:08 +00:00
2009-04-02 16:15:57 +00:00
$ c - > stash - > { template } = 'jobset.tt' ;
2011-05-16 08:03:06 +00:00
2010-02-09 13:47:20 +00:00
my $ projectName = $ c - > stash - > { project } - > name ;
my $ jobsetName = $ c - > stash - > { jobset } - > name ;
# Get the active / inactive jobs in this jobset.
my @ jobs = $ c - > stash - > { jobset } - > jobs - > search (
{ } ,
{ select = > [
"name" ,
2011-11-29 18:08:23 +01:00
\ ( "exists (select 1 from builds where project = '$projectName' and jobset = '$jobsetName' and job = me.name and isCurrent = 1) as active" )
2010-02-09 13:47:20 +00:00
]
, as = > [ "name" , "active" ]
, order_by = > [ "name" ] } ) ;
$ c - > stash - > { activeJobs } = [] ;
$ c - > stash - > { inactiveJobs } = [] ;
foreach my $ job ( @ jobs ) {
if ( $ job - > get_column ( 'active' ) ) {
push @ { $ c - > stash - > { activeJobs } } , $ job - > name ;
} else {
push @ { $ c - > stash - > { inactiveJobs } } , $ job - > name ;
}
}
2011-05-16 08:03:06 +00:00
2012-04-15 20:06:42 +00:00
$ c - > stash - > { evals } = getEvals ( $ self , $ c , 0 , 5 ) ;
2012-04-13 11:26:37 +02:00
2011-11-29 18:08:23 +01:00
$ c - > stash - > { systems } =
[ $ c - > stash - > { jobset } - > builds - > search ( { iscurrent = > 1 } , { select = > [ "system" ] , distinct = > 1 , order_by = > "system" } ) ] ;
2011-05-16 08:03:06 +00:00
2010-02-05 14:48:22 +00:00
# status per system
my @ systems = ( ) ;
foreach my $ system ( @ { $ c - > stash - > { systems } } ) {
push ( @ systems , $ system - > system ) ;
}
2011-05-16 08:03:06 +00:00
2011-08-29 17:56:38 +00:00
if ( $ forceStatus || scalar ( @ { $ c - > stash - > { activeJobs } } ) <= 50 ) {
2010-02-09 13:47:20 +00:00
my @ select = ( ) ;
my @ as = ( ) ;
push ( @ select , "job" ) ; push ( @ as , "job" ) ;
foreach my $ system ( @ systems ) {
2012-03-05 21:52:47 +01:00
push ( @ select , "(select buildstatus from Builds b where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))" ) ;
2010-02-09 13:47:20 +00:00
push ( @ as , $ system ) ;
2012-03-05 21:52:47 +01:00
push ( @ select , "(select b.id from Builds b where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))" ) ;
2012-02-29 02:22:49 +01:00
push ( @ as , "$system-build" ) ;
2010-02-09 13:47:20 +00:00
}
$ c - > stash - > { activeJobsStatus } =
[ $ c - > model ( 'DB' ) - > resultset ( 'ActiveJobsForJobset' ) - > search (
{ } ,
{ bind = > [ $ c - > stash - > { project } - > name , $ c - > stash - > { jobset } - > name ]
, select = > \ @ select
, as = > \ @ as
, order_by = > [ "job" ]
} ) ] ;
}
2011-05-16 08:03:06 +00:00
2009-03-13 15:23:08 +00:00
}
2012-02-21 17:59:36 +01:00
2010-02-09 13:43:53 +00:00
sub index : Chained('jobset') PathPart('') Args(0) {
2012-02-21 17:59:36 +01:00
my ( $ self , $ c ) = @ _ ;
jobsetIndex ( $ self , $ c , 0 ) ;
2010-02-09 13:43:53 +00:00
}
2012-02-21 17:59:36 +01:00
2010-02-09 13:43:53 +00:00
sub indexWithStatus : Chained('jobset') PathPart('') Args(1) {
2012-02-21 17:59:36 +01:00
my ( $ self , $ c , $ forceStatus ) = @ _ ;
jobsetIndex ( $ self , $ c , 1 ) ;
2010-02-09 13:43:53 +00:00
}
2009-03-13 15:23:08 +00:00
# Hydra::Base::Controller::ListBuilds needs this.
sub get_builds : Chained('jobset') PathPart('') CaptureArgs(0) {
my ( $ self , $ c ) = @ _ ;
2009-03-13 17:32:08 +00:00
$ c - > stash - > { allBuilds } = $ c - > stash - > { jobset } - > builds ;
2009-04-03 15:37:21 +00:00
$ c - > stash - > { jobStatus } = $ c - > model ( 'DB' ) - > resultset ( 'JobStatusForJobset' )
- > search ( { } , { bind = > [ $ c - > stash - > { project } - > name , $ c - > stash - > { jobset } - > name ] } ) ;
2009-04-08 22:08:00 +00:00
$ c - > stash - > { allJobsets } = $ c - > stash - > { jobset_ } ;
$ c - > stash - > { allJobs } = $ c - > stash - > { jobset } - > jobs ;
2009-04-03 15:37:21 +00:00
$ c - > stash - > { latestSucceeded } = $ c - > model ( 'DB' ) - > resultset ( 'LatestSucceededForJobset' )
- > search ( { } , { bind = > [ $ c - > stash - > { project } - > name , $ c - > stash - > { jobset } - > name ] } ) ;
2009-03-13 15:23:08 +00:00
$ c - > stash - > { channelBaseName } =
2009-03-13 15:41:19 +00:00
$ c - > stash - > { project } - > name . "-" . $ c - > stash - > { jobset } - > name ;
2009-03-13 15:23:08 +00:00
}
2009-04-02 16:15:57 +00:00
sub edit : Chained('jobset') PathPart Args(0) {
my ( $ self , $ c ) = @ _ ;
2011-05-16 08:03:06 +00:00
2009-04-02 16:15:57 +00:00
requireProjectOwner ( $ c , $ c - > stash - > { project } ) ;
$ c - > stash - > { template } = 'jobset.tt' ;
$ c - > stash - > { edit } = 1 ;
}
sub submit : Chained('jobset') PathPart Args(0) {
my ( $ self , $ c ) = @ _ ;
2011-05-16 08:03:06 +00:00
2009-04-02 16:15:57 +00:00
requireProjectOwner ( $ c , $ c - > stash - > { project } ) ;
requirePost ( $ c ) ;
2011-05-16 08:03:06 +00:00
2009-04-22 22:43:04 +00:00
txn_do ( $ c - > model ( 'DB' ) - > schema , sub {
2009-04-02 16:15:57 +00:00
updateJobset ( $ c , $ c - > stash - > { jobset } ) ;
} ) ;
$ c - > res - > redirect ( $ c - > uri_for ( $ self - > action_for ( "index" ) ,
[ $ c - > stash - > { project } - > name , $ c - > stash - > { jobset } - > name ] ) ) ;
}
2010-06-04 14:43:28 +00:00
sub hide : Chained('jobset') PathPart Args(0) {
my ( $ self , $ c ) = @ _ ;
requireProjectOwner ( $ c , $ c - > stash - > { project } ) ;
2011-05-16 08:03:06 +00:00
2010-06-04 14:43:28 +00:00
txn_do ( $ c - > model ( 'DB' ) - > schema , sub {
$ c - > stash - > { jobset } - > update ( { hidden = > 1 , enabled = > 0 } ) ;
} ) ;
2011-05-16 08:03:06 +00:00
2010-06-04 14:43:28 +00:00
$ c - > res - > redirect ( $ c - > uri_for ( $ c - > controller ( 'Project' ) - > action_for ( "view" ) ,
[ $ c - > stash - > { project } - > name ] ) ) ;
}
2012-02-21 17:59:36 +01:00
2010-06-04 14:43:28 +00:00
sub unhide : Chained('jobset') PathPart Args(0) {
my ( $ self , $ c ) = @ _ ;
requireProjectOwner ( $ c , $ c - > stash - > { project } ) ;
2011-05-16 08:03:06 +00:00
2010-06-04 14:43:28 +00:00
txn_do ( $ c - > model ( 'DB' ) - > schema , sub {
$ c - > stash - > { jobset } - > update ( { hidden = > 0 } ) ;
} ) ;
2011-05-16 08:03:06 +00:00
2010-06-04 14:43:28 +00:00
$ c - > res - > redirect ( $ c - > uri_for ( $ c - > controller ( 'Project' ) - > action_for ( "view" ) ,
[ $ c - > stash - > { project } - > name ] ) ) ;
}
2012-02-21 17:59:36 +01:00
2009-04-02 16:15:57 +00:00
sub delete : Chained('jobset') PathPart Args(0) {
my ( $ self , $ c ) = @ _ ;
requireProjectOwner ( $ c , $ c - > stash - > { project } ) ;
requirePost ( $ c ) ;
2011-05-16 08:03:06 +00:00
2009-04-22 22:43:04 +00:00
txn_do ( $ c - > model ( 'DB' ) - > schema , sub {
2009-04-02 16:15:57 +00:00
$ c - > stash - > { jobset } - > delete ;
} ) ;
2011-05-16 08:03:06 +00:00
2009-04-02 16:15:57 +00:00
$ c - > res - > redirect ( $ c - > uri_for ( $ c - > controller ( 'Project' ) - > action_for ( "view" ) ,
[ $ c - > stash - > { project } - > name ] ) ) ;
}
2009-10-26 15:39:14 +00:00
sub nixExprPathFromParams {
my ( $ c ) = @ _ ;
2011-05-16 08:03:06 +00:00
2009-04-02 16:15:57 +00:00
# The Nix expression path must be relative and can't contain ".." elements.
my $ nixExprPath = trim $ c - > request - > params - > { "nixexprpath" } ;
error ( $ c , "Invalid Nix expression path: $nixExprPath" ) if $ nixExprPath !~ /^$relPathRE$/ ;
my $ nixExprInput = trim $ c - > request - > params - > { "nixexprinput" } ;
error ( $ c , "Invalid Nix expression input name: $nixExprInput" ) unless $ nixExprInput =~ /^\w+$/ ;
2009-10-26 15:39:14 +00:00
return ( $ nixExprPath , $ nixExprInput ) ;
}
sub checkInput {
my ( $ c , $ baseName ) = @ _ ;
my $ inputName = trim $ c - > request - > params - > { "input-$baseName-name" } ;
error ( $ c , "Invalid input name: $inputName" ) unless $ inputName =~ /^[[:alpha:]]\w*$/ ;
my $ inputType = trim $ c - > request - > params - > { "input-$baseName-type" } ;
error ( $ c , "Invalid input type: $inputType" ) unless
2010-07-27 16:09:35 +00:00
$ inputType eq "svn" || $ inputType eq "svn-checkout" || $ inputType eq "hg" || $ inputType eq "tarball" ||
2011-02-08 13:37:50 +00:00
$ inputType eq "string" || $ inputType eq "path" || $ inputType eq "boolean" || $ inputType eq "bzr" || $ inputType eq "bzr-checkout" ||
2010-01-19 14:15:31 +00:00
$ inputType eq "git" || $ inputType eq "build" || $ inputType eq "sysbuild" ;
2009-10-26 15:39:14 +00:00
return ( $ inputName , $ inputType ) ;
}
sub checkInputValue {
my ( $ c , $ type , $ value ) = @ _ ;
$ value = trim $ value ;
error ( $ c , "Invalid Boolean value: $value" ) if
$ type eq "boolean" && ! ( $ value eq "true" || $ value eq "false" ) ;
return $ value ;
}
sub updateJobset {
my ( $ c , $ jobset ) = @ _ ;
my $ jobsetName = trim $ c - > request - > params - > { "name" } ;
2012-04-17 08:53:00 +00:00
error ( $ c , "Invalid jobset name: ‘ $jobsetName’ " ) if $ jobsetName !~ /^$jobsetNameRE$/ ;
2009-10-26 15:39:14 +00:00
my ( $ nixExprPath , $ nixExprInput ) = nixExprPathFromParams $ c ;
2009-04-02 16:15:57 +00:00
$ jobset - > update (
{ name = > $ jobsetName
, description = > trim ( $ c - > request - > params - > { "description" } )
, nixexprpath = > $ nixExprPath
, nixexprinput = > $ nixExprInput
2009-10-08 11:39:16 +00:00
, enabled = > trim ( $ c - > request - > params - > { enabled } ) eq "1" ? 1 : 0
2010-01-06 13:07:59 +00:00
, enableemail = > trim ( $ c - > request - > params - > { enableemail } ) eq "1" ? 1 : 0
2011-03-07 15:55:37 +00:00
, emailoverride = > trim ( $ c - > request - > params - > { emailoverride } ) || ""
2011-05-16 08:03:06 +00:00
, keepnr = > trim ( $ c - > request - > params - > { keepnr } ) || 3
2009-04-02 16:15:57 +00:00
} ) ;
my % inputNames ;
2011-05-16 08:03:06 +00:00
2009-04-02 16:15:57 +00:00
# Process the inputs of this jobset.
foreach my $ param ( keys % { $ c - > request - > params } ) {
next unless $ param =~ /^input-(\w+)-name$/ ;
2009-10-26 15:39:14 +00:00
my $ baseName = $ 1 ;
next if $ baseName eq "template" ;
2009-04-02 16:15:57 +00:00
2009-10-26 15:39:14 +00:00
my ( $ inputName , $ inputType ) = checkInput ( $ c , $ baseName ) ;
2009-04-02 16:15:57 +00:00
$ inputNames { $ inputName } = 1 ;
2011-05-16 08:03:06 +00:00
2009-04-02 16:15:57 +00:00
my $ input ;
2009-10-26 15:39:14 +00:00
if ( $ baseName =~ /^\d+$/ ) { # numeric base name is auto-generated, i.e. a new entry
2009-04-02 16:15:57 +00:00
$ input = $ jobset - > jobsetinputs - > create (
{ name = > $ inputName
, type = > $ inputType
} ) ;
} else { # it's an existing input
2009-10-26 15:39:14 +00:00
$ input = ( $ jobset - > jobsetinputs - > search ( { name = > $ baseName } ) ) [ 0 ] ;
2009-04-02 16:15:57 +00:00
die unless defined $ input ;
$ input - > update ( { name = > $ inputName , type = > $ inputType } ) ;
}
# Update the values for this input. Just delete all the
# current ones, then create the new values.
$ input - > jobsetinputalts - > delete_all ;
2009-10-26 15:39:14 +00:00
my $ values = $ c - > request - > params - > { "input-$baseName-values" } ;
2009-04-02 16:15:57 +00:00
$ values = [] unless defined $ values ;
$ values = [ $ values ] unless ref ( $ values ) eq 'ARRAY' ;
my $ altnr = 0 ;
foreach my $ value ( @ { $ values } ) {
2009-10-26 15:39:14 +00:00
$ value = checkInputValue ( $ c , $ inputType , $ value ) ;
2009-04-02 16:15:57 +00:00
$ input - > jobsetinputalts - > create ( { altnr = > $ altnr + + , value = > $ value } ) ;
}
}
# Get rid of deleted inputs.
my @ inputs = $ jobset - > jobsetinputs - > all ;
foreach my $ input ( @ inputs ) {
$ input - > delete unless defined $ inputNames { $ input - > name } ;
}
}
2010-04-23 11:20:40 +00:00
sub clone : Chained('jobset') PathPart('clone') Args(0) {
my ( $ self , $ c ) = @ _ ;
my $ jobset = $ c - > stash - > { jobset } ;
requireProjectOwner ( $ c , $ jobset - > project ) ;
$ c - > stash - > { template } = 'clone-jobset.tt' ;
}
2012-02-21 17:59:36 +01:00
2010-04-23 11:20:40 +00:00
sub clone_submit : Chained('jobset') PathPart('clone/submit') Args(0) {
my ( $ self , $ c ) = @ _ ;
my $ jobset = $ c - > stash - > { jobset } ;
requireProjectOwner ( $ c , $ jobset - > project ) ;
requirePost ( $ c ) ;
2012-04-17 08:53:00 +00:00
my $ newJobsetName = trim $ c - > request - > params - > { "newjobset" } ;
error ( $ c , "Invalid jobset name: $newJobsetName" ) unless $ newJobsetName =~ /^[[:alpha:]][\w\-]*$/ ;
2010-04-23 11:20:40 +00:00
2012-04-17 08:53:00 +00:00
my $ newJobset ;
2011-05-16 08:03:06 +00:00
txn_do ( $ c - > model ( 'DB' ) - > schema , sub {
2012-04-17 08:53:00 +00:00
$ newJobset = $ jobset - > project - > jobsets - > create (
{ name = > $ newJobsetName
2010-04-23 11:20:40 +00:00
, description = > $ jobset - > description
, nixexprpath = > $ jobset - > nixexprpath
, nixexprinput = > $ jobset - > nixexprinput
, enabled = > 0
2011-05-16 08:03:06 +00:00
, enableemail = > $ jobset - > enableemail
2011-03-07 15:55:37 +00:00
, emailoverride = > $ jobset - > emailoverride || ""
2011-05-16 08:03:06 +00:00
} ) ;
2010-04-23 11:20:40 +00:00
foreach my $ input ( $ jobset - > jobsetinputs ) {
2012-04-17 08:53:00 +00:00
my $ newinput = $ newJobset - > jobsetinputs - > create ( { name = > $ input - > name , type = > $ input - > type } ) ;
2010-04-23 11:20:40 +00:00
foreach my $ inputalt ( $ input - > jobsetinputalts ) {
$ newinput - > jobsetinputalts - > create ( { altnr = > $ inputalt - > altnr , value = > $ inputalt - > value } ) ;
}
}
} ) ;
2011-05-16 08:03:06 +00:00
2012-04-17 08:53:00 +00:00
$ c - > res - > redirect ( $ c - > uri_for ( $ c - > controller ( 'Jobset' ) - > action_for ( "edit" ) , [ $ jobset - > project - > name , $ newJobsetName ] ) ) ;
2010-04-23 11:20:40 +00:00
}
2012-04-15 18:47:22 +00:00
sub getEvals {
my ( $ self , $ c , $ offset , $ rows ) = @ _ ;
2012-04-15 20:06:42 +00:00
my @ evals = $ c - > stash - > { jobset } - > jobsetevals - > search (
2012-04-15 18:47:22 +00:00
{ hasnewbuilds = > 1 } ,
2012-04-15 22:11:20 +00:00
{ order_by = > "id DESC" , rows = > $ rows + 1 , offset = > $ offset } ) ;
2012-04-15 20:06:42 +00:00
my @ res = ( ) ;
2012-04-15 21:49:54 +00:00
my $ prevInputs = [] ;
2012-04-15 22:11:20 +00:00
my $ prev ;
2012-04-15 21:49:54 +00:00
for ( my $ n = scalar @ evals - 1 ; $ n >= 0 ; $ n - - ) {
2012-04-15 20:06:42 +00:00
my $ cur = $ evals [ $ n ] ;
2012-04-15 22:11:20 +00:00
# Get stats for this eval.
2012-04-15 22:57:10 +00:00
my $ nrScheduled ;
my $ nrSucceeded = $ cur - > nrsucceeded ;
if ( defined $ nrSucceeded ) {
$ nrScheduled = 0 ;
} else {
$ nrScheduled = $ cur - > builds - > search ( { finished = > 0 } ) - > count ;
$ nrSucceeded = $ cur - > builds - > search ( { finished = > 1 , buildStatus = > 0 } ) - > count ;
if ( $ nrScheduled == 0 ) {
$ cur - > update ( { nrsucceeded = > $ nrSucceeded } ) ;
}
}
2012-04-15 20:06:42 +00:00
# Compute what inputs changed between each eval.
2012-04-15 21:49:54 +00:00
my $ curInputs = [ $ cur - > jobsetevalinputs - > search (
2012-05-25 04:14:36 +02:00
{ - or = > [ - and = > [ uri = > { '!=' = > undef } , revision = > { '!=' = > undef } ] , dependency = > { '!=' = > undef } ] , altNr = > 0 } ,
2012-04-15 21:49:54 +00:00
{ order_by = > "name" } ) ] ;
2012-04-15 20:06:42 +00:00
my @ changedInputs ;
my % prevInputsHash ;
$ prevInputsHash { $ _ - > name } = $ _ foreach @ { $ prevInputs } ;
foreach my $ input ( @ { $ curInputs } ) {
my $ p = $ prevInputsHash { $ input - > name } ;
push @ changedInputs , $ input
2012-05-25 04:14:36 +02:00
if ! defined $ p || $ input - > revision ne $ p - > revision || $ input - > type ne $ p - > type || $ input - > uri ne $ p - > uri ||
( defined $ input - > dependency && defined $ p - > dependency && $ input - > dependency - > id ne $ p - > dependency - > id ) ;
2012-04-15 20:06:42 +00:00
}
2012-04-15 21:49:54 +00:00
$ prevInputs = $ curInputs ;
2012-04-15 22:11:20 +00:00
my $ e =
2012-04-15 21:49:54 +00:00
{ eval = > $ cur
2012-04-15 22:11:20 +00:00
, nrScheduled = > $ nrScheduled
, nrSucceeded = > $ nrSucceeded
2012-04-15 22:57:10 +00:00
, nrFailed = > $ cur - > nrbuilds - $ nrSucceeded - $ nrScheduled
2012-04-15 22:11:20 +00:00
, diff = > defined $ prev ? $ nrSucceeded - $ prev - > { nrSucceeded } : 0
2012-04-15 21:49:54 +00:00
, changedInputs = > [ @ changedInputs ]
} ;
2012-04-15 22:11:20 +00:00
push @ res , $ e if $ n < $ rows ;
$ prev = $ e ;
2012-04-15 20:06:42 +00:00
}
2012-04-15 22:11:20 +00:00
return [ reverse @ res ] ;
2012-04-15 18:47:22 +00:00
}
2012-04-02 16:11:22 +02:00
sub evals : Chained('jobset') PathPart('evals') Args(0) {
my ( $ self , $ c ) = @ _ ;
$ c - > stash - > { template } = 'jobset-evals.tt' ;
my $ page = int ( $ c - > req - > param ( 'page' ) || "1" ) || 1 ;
my $ resultsPerPage = 20 ;
$ c - > stash - > { page } = $ page ;
$ c - > stash - > { resultsPerPage } = $ resultsPerPage ;
$ c - > stash - > { total } = $ c - > stash - > { jobset } - > jobsetevals - > search ( { hasnewbuilds = > 1 } ) - > count ;
2012-04-15 20:06:42 +00:00
$ c - > stash - > { evals } = getEvals ( $ self , $ c , ( $ page - 1 ) * $ resultsPerPage , $ resultsPerPage )
2012-04-02 16:11:22 +02:00
}
2010-04-23 11:20:40 +00:00
2012-04-03 01:30:54 +02:00
# Redirect to the latest finished evaluation of this jobset.
sub latest_eval : Chained('jobset') PathPart('latest-eval') {
my ( $ self , $ c , @ args ) = @ _ ;
2012-04-03 11:28:59 +02:00
my $ eval = getLatestFinishedEval ( $ c , $ c - > stash - > { jobset } )
or notFound ( $ c , "No evaluation found." ) ;
2012-04-04 12:56:49 +02:00
$ c - > res - > redirect ( $ c - > uri_for ( $ c - > controller ( 'JobsetEval' ) - > action_for ( "view" ) , [ $ eval - > id ] , @ args , $ c - > req - > params ) ) ;
2012-04-03 01:30:54 +02:00
}
2009-03-13 15:23:08 +00:00
1 ;