- Fixes for rt.cpan #17322 and #17331
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Helper.pm
index 0d246f2..8d3fbb7 100644 (file)
@@ -8,7 +8,6 @@ use File::Path;
 use IO::File;
 use FindBin;
 use Template;
-use Catalyst;
 use Catalyst::Utils;
 use Catalyst::Exception;
 
@@ -58,31 +57,49 @@ Create the main application skeleton.
 
 sub mk_app {
     my ( $self, $name ) = @_;
-    return 0 if $name =~ /[^\w\:]/;
+
+    # Needs to be here for PAR
+    require Catalyst;
+
+    if ( $name =~ /[^\w\:]/ ) {
+        warn "Error: Invalid application name.\n";
+        return 0;
+    }
     $self->{name} = $name;
     $self->{dir}  = $name;
     $self->{dir} =~ s/\:\:/-/g;
+    $self->{script}    = File::Spec->catdir( $self->{dir}, 'script' );
     $self->{appprefix} = Catalyst::Utils::appprefix($name);
-    $self->{startperl} = $Config{startperl};
+    $self->{startperl} = "#!$Config{perlpath} -w";
     $self->{scriptgen} = $Catalyst::CATALYST_SCRIPT_GEN || 4;
     $self->{author}    = $self->{author} = $ENV{'AUTHOR'}
       || eval { @{ [ getpwuid($<) ] }[6] }
       || 'Catalyst developer';
-    $self->_mk_dirs;
-    $self->_mk_appclass;
-    $self->_mk_build;
-    $self->_mk_makefile;
-    $self->_mk_readme;
-    $self->_mk_changes;
-    $self->_mk_apptest;
-    $self->_mk_cgi;
-    $self->_mk_fastcgi;
-    $self->_mk_server;
-    $self->_mk_test;
-    $self->_mk_create;
-    $self->_mk_images;
-    $self->_mk_favicon;
-    return 1;
+
+    my $gen_scripts  = ( $self->{makefile} ) ? 0 : 1;
+    my $gen_makefile = ( $self->{scripts} )  ? 0 : 1;
+    my $gen_app = ( $self->{scripts} || $self->{makefile} ) ? 0 : 1;
+
+    if ($gen_app) {
+        $self->_mk_dirs;
+        $self->_mk_appclass;
+        $self->_mk_readme;
+        $self->_mk_changes;
+        $self->_mk_apptest;
+        $self->_mk_images;
+        $self->_mk_favicon;
+    }
+    if ($gen_makefile) {
+        $self->_mk_makefile;
+    }
+    if ($gen_scripts) {
+        $self->_mk_cgi;
+        $self->_mk_fastcgi;
+        $self->_mk_server;
+        $self->_mk_test;
+        $self->_mk_create;
+    }
+    return $self->{dir};
 }
 
 =head3 mk_component
@@ -99,8 +116,8 @@ sub mk_component {
     $self->{author} = $self->{author} = $ENV{'AUTHOR'}
       || eval { @{ [ getpwuid($<) ] }[6] }
       || 'A clever guy';
-    $self->{base} = File::Spec->catdir( $FindBin::Bin, '..' );
-    unless ( $_[0] =~ /^(?:model|m|view|v|controller|c)$/i ) {
+    $self->{base} ||= File::Spec->catdir( $FindBin::Bin, '..' );
+    unless ( $_[0] =~ /^(?:model|view|controller)$/i ) {
         my $helper = shift;
         my @args   = @_;
         my $class  = "Catalyst::Helper::$helper";
@@ -121,15 +138,20 @@ sub mk_component {
         my $helper = shift;
         my @args   = @_;
         return 0 if $name =~ /[^\w\:]/;
-        $type = 'M' if $type =~ /model|m/i;
-        $type = 'V' if $type =~ /view|v/i;
-        $type = 'C' if $type =~ /controller|c/i;
+        $type              = lc $type;
+        $self->{long_type} = ucfirst $type;
+        $type              = 'M' if $type =~ /model/i;
+        $type              = 'V' if $type =~ /view/i;
+        $type              = 'C' if $type =~ /controller/i;
+        my $appdir = File::Spec->catdir( split /\:\:/, $app );
+        my $test_path =
+          File::Spec->catdir( $FindBin::Bin, '..', 'lib', $appdir, 'C' );
+        $type = $self->{long_type} unless -d $test_path;
         $self->{type}  = $type;
         $self->{name}  = $name;
         $self->{class} = "$app\::$type\::$name";
 
         # Class
-        my $appdir = File::Spec->catdir( split /\:\:/, $app );
         my $path =
           File::Spec->catdir( $FindBin::Bin, '..', 'lib', $appdir, $type );
         my $file = $name;
@@ -137,8 +159,8 @@ sub mk_component {
             my @path = split /\:\:/, $name;
             $file = pop @path;
             $path = File::Spec->catdir( $path, @path );
-            mkpath [$path];
         }
+        $self->mk_dir($path);
         $file = File::Spec->catfile( $path, "$file.pm" );
         $self->{file} = $file;
 
@@ -148,9 +170,7 @@ sub mk_component {
 
         # Helper
         if ($helper) {
-            my $comp = 'Model';
-            $comp = 'View'       if $type eq 'V';
-            $comp = 'Controller' if $type eq 'C';
+            my $comp  = $self->{long_type};
             my $class = "Catalyst::Helper::$comp\::$helper";
             eval "require $class";
 
@@ -209,12 +229,17 @@ sub mk_file {
     my ( $self, $file, $content ) = @_;
     if ( -e $file ) {
         print qq/ exists "$file"\n/;
-        return 0 unless $self->{'.newfiles'};
-        if ( my $f = IO::File->new("< $file") ) {
-            my $oldcontent = join( '', (<$f>) );
-            return 0 if $content eq $oldcontent;
+        return 0
+          unless ( $self->{'.newfiles'}
+            || $self->{scripts}
+            || $self->{makefile} );
+        if ( $self->{'.newfiles'} ) {
+            if ( my $f = IO::File->new("< $file") ) {
+                my $oldcontent = join( '', (<$f>) );
+                return 0 if $content eq $oldcontent;
+            }
+            $file .= '.new';
         }
-        $file .= '.new';
     }
     if ( my $f = IO::File->new("> $file") ) {
         binmode $f;
@@ -245,8 +270,9 @@ sub next_test {
         $self->{uri} = $prefix;
     }
     my $dir  = $self->{test_dir};
-    my $type = $self->{type};
-    return File::Spec->catfile( $dir, $type, $tname );
+    my $type = lc $self->{type};
+    $self->mk_dir($dir);
+    return File::Spec->catfile( $dir, "$type\_$tname" );
 }
 
 =head3 render_file
@@ -272,7 +298,6 @@ sub render_file {
 sub _mk_dirs {
     my $self = shift;
     $self->mk_dir( $self->{dir} );
-    $self->{script} = File::Spec->catdir( $self->{dir}, 'script' );
     $self->mk_dir( $self->{script} );
     $self->{lib} = File::Spec->catdir( $self->{dir}, 'lib' );
     $self->mk_dir( $self->{lib} );
@@ -284,18 +309,27 @@ sub _mk_dirs {
     $self->mk_dir( $self->{images} );
     $self->{t} = File::Spec->catdir( $self->{dir}, 't' );
     $self->mk_dir( $self->{t} );
-    $self->mk_dir( File::Spec->catdir( $self->{t}, 'M' ) );
-    $self->mk_dir( File::Spec->catdir( $self->{t}, 'V' ) );
-    $self->mk_dir( File::Spec->catdir( $self->{t}, 'C' ) );
+
     $self->{class} = File::Spec->catdir( split( /\:\:/, $self->{name} ) );
     $self->{mod} = File::Spec->catdir( $self->{lib}, $self->{class} );
     $self->mk_dir( $self->{mod} );
-    $self->{m} = File::Spec->catdir( $self->{mod}, 'M' );
-    $self->mk_dir( $self->{m} );
-    $self->{v} = File::Spec->catdir( $self->{mod}, 'V' );
-    $self->mk_dir( $self->{v} );
-    $self->{c} = File::Spec->catdir( $self->{mod}, 'C' );
-    $self->mk_dir( $self->{c} );
+
+    if ( $self->{short} ) {
+        $self->{m} = File::Spec->catdir( $self->{mod}, 'M' );
+        $self->mk_dir( $self->{m} );
+        $self->{v} = File::Spec->catdir( $self->{mod}, 'V' );
+        $self->mk_dir( $self->{v} );
+        $self->{c} = File::Spec->catdir( $self->{mod}, 'C' );
+        $self->mk_dir( $self->{c} );
+    }
+    else {
+        $self->{m} = File::Spec->catdir( $self->{mod}, 'Model' );
+        $self->mk_dir( $self->{m} );
+        $self->{v} = File::Spec->catdir( $self->{mod}, 'View' );
+        $self->mk_dir( $self->{v} );
+        $self->{c} = File::Spec->catdir( $self->{mod}, 'Controller' );
+        $self->mk_dir( $self->{c} );
+    }
     $self->{base} = File::Spec->rel2abs( $self->{dir} );
 }
 
@@ -305,16 +339,19 @@ sub _mk_appclass {
     $self->render_file( 'appclass', "$mod.pm" );
 }
 
-sub _mk_build {
-    my $self = shift;
-    my $dir  = $self->{dir};
-    $self->render_file( 'build', "$dir\/Build.PL" );
-}
-
 sub _mk_makefile {
     my $self = shift;
-    my $dir  = $self->{dir};
+    $self->{path} = File::Spec->catfile( 'lib', split( '::', $self->{name} ) );
+    $self->{path} .= '.pm';
+    my $dir = $self->{dir};
     $self->render_file( 'makefile', "$dir\/Makefile.PL" );
+
+    if ( $self->{makefile} ) {
+
+        # deprecate the old Build.PL file when regenerating Makefile.PL
+        $self->_deprecate_file(
+            File::Spec->catdir( $self->{dir}, 'Build.PL' ) );
+    }
 }
 
 sub _mk_readme {
@@ -413,6 +450,27 @@ sub _mk_favicon {
 
 }
 
+sub _deprecate_file {
+    my ( $self, $file ) = @_;
+    if ( -e $file ) {
+        my $oldcontent;
+        if ( my $f = IO::File->new("< $file") ) {
+            $oldcontent = join( '', (<$f>) );
+        }
+        my $newfile = $file . '.deprecated';
+        if ( my $f = IO::File->new("> $newfile") ) {
+            binmode $f;
+            print $f $oldcontent;
+            print qq/created "$newfile"\n/;
+            unlink $file;
+            print qq/removed "$file"\n/;
+            return 1;
+        }
+        Catalyst::Exception->throw(
+            message => qq/Couldn't create "$file", "$!"/ );
+    }
+}
+
 =head1 HELPERS
 
 Helpers are classes that provide two methods.
@@ -463,16 +521,25 @@ package [% name %];
 use strict;
 use warnings;
 
-# -Debug activates the debug mode for very useful log messages
-# Static::Simple will serve static files from the root directory
+#
+# Set flags and add plugins for the application
+#
+#         -Debug: activates the debug mode for very useful log messages
+# Static::Simple: will serve static files from the application's root 
+# directory
+#
 use Catalyst qw/-Debug Static::Simple/;
 
 our $VERSION = '0.01';
 
+#
 # Configure the application
-__PACKAGE__->config( name => '[% name %]' );
+#
+__PACKAGE__->config( { name => '[% name %]' } );
 
+#
 # Start the application
+#
 __PACKAGE__->setup;
 
 =head1 NAME
@@ -489,13 +556,15 @@ Catalyst based application.
 
 =head1 METHODS
 
-=over 4
+=cut
 
-=item default
+=head2 default
 
 =cut
 
+#
 # Output a friendly welcome message
+#
 sub default : Private {
     my ( $self, $c ) = @_;
 
@@ -503,8 +572,10 @@ sub default : Private {
     $c->response->body( $c->welcome_message );
 }
 
-# Uncomment and modify this end action after adding a View class
-#=item end
+#
+# Uncomment and modify this end action after adding a View component
+#
+#=head2 end
 #
 #=cut
 #
@@ -512,11 +583,9 @@ sub default : Private {
 #    my ( $self, $c ) = @_;
 #
 #    # Forward to View unless response body is already defined
-#    $c->forward('MyApp::V::') unless $c->response->body;
+#    $c->forward( $c->view('') ) unless $c->response->body;
 #}
 
-=back
-
 =head1 AUTHOR
 
 [% author %]
@@ -530,58 +599,28 @@ it under the same terms as Perl itself.
 
 1;
 __makefile__
-    unless ( eval "use Module::Build::Compat 0.02; 1" ) {
-        print "This module requires Module::Build to install itself.\n";
-
-        require ExtUtils::MakeMaker;
-        my $yn =
-          ExtUtils::MakeMaker::prompt( '  Install Module::Build now from CPAN?',            'y' );
+use inc::Module::Install;
 
-        unless ( $yn =~ /^y/i ) {
-            die " *** Cannot install without Module::Build.  Exiting ...\n";
-        }
+name '[% dir %]';
+all_from '[% path %]';
 
-        require Cwd;
-        require File::Spec;
-        require CPAN;
+requires Catalyst => '5.62';
 
-        # Save this 'cause CPAN will chdir all over the place.
-        my $cwd      = Cwd::cwd();
-        my $makefile = File::Spec->rel2abs($0);
+catalyst;
 
-        CPAN::Shell->install('Module::Build::Compat')
-          or die " *** Cannot install without Module::Build.  Exiting ...\n";
-
-        chdir $cwd or die "Cannot chdir() back to $cwd: $!";
-    }
-    eval "use Module::Build::Compat 0.02; 1" or die $@;
-    use lib '_build/lib';
-    Module::Build::Compat->run_build_pl( args => \@ARGV );
-    require Module::Build;
-    Module::Build::Compat->write_makefile( build_class => 'Module::Build' );
-__build__
-use strict;
-use Catalyst::Build;
-
-my $build = Catalyst::Build->new(
-    create_makefile_pl => 'passthrough',
-    license            => 'perl',
-    module_name        => '[% name %]',
-    requires           => { Catalyst => '5.10' },
-    create_makefile_pl => 'passthrough',
-    script_files       => [ glob('script/*') ],
-    test_files         => [ glob('t/*.t'), glob('t/*/*.t') ]
-);
-$build->create_build_script;
+install_script glob('script/*.pl');
+auto_install;
+WriteAll;
 __readme__
 Run script/[% appprefix %]_server.pl to test the application.
 __changes__
 This file documents the revision history for Perl extension [% name %].
+
 0.01  [% time %]
         - initial revision, generated by Catalyst
 __apptest__
 use Test::More tests => 2;
-use_ok( Catalyst::Test, '[% name %]' );
+BEGIN { use_ok( Catalyst::Test, '[% name %]' ); }
 
 ok( request('/')->is_success );
 __podtest__
@@ -601,7 +640,7 @@ plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
 
 all_pod_coverage_ok();
 __cgi__
-[% startperl %] -w
+[% startperl %]
 
 BEGIN { $ENV{CATALYST_ENGINE} ||= 'CGI' }
 
@@ -639,7 +678,7 @@ it under the same terms as Perl itself.
 
 =cut
 __fastcgi__
-[% startperl %] -w
+[% startperl %]
 
 BEGIN { $ENV{CATALYST_ENGINE} ||= 'FastCGI' }
 
@@ -651,17 +690,27 @@ use lib "$FindBin::Bin/../lib";
 use [% name %];
 
 my $help = 0;
-my ( $listen, $nproc );
+my ( $listen, $nproc, $pidfile, $manager, $detach );
  
 GetOptions(
-    'help|?'     => \$help,
-    'listen|l=s' => \$listen,
-    'nproc|n=i'  => \$nproc,
+    'help|?'      => \$help,
+    'listen|l=s'  => \$listen,
+    'nproc|n=i'   => \$nproc,
+    'pidfile|p=s' => \$pidfile,
+    'manager|M=s' => \$manager,
+    'daemon|d'    => \$detach,
 );
 
 pod2usage(1) if $help;
 
-[% name %]->run( $listen, { nproc => $nproc } );
+[% name %]->run( 
+    $listen, 
+    {   nproc   => $nproc,
+        pidfile => $pidfile, 
+        manager => $manager,
+        detach  => $detach,
+    }
+);
 
 1;
 
@@ -680,7 +729,14 @@ pod2usage(1) if $help;
                  can be HOST:PORT, :PORT or a
                  filesystem path
    -n -nproc     specify number of processes to keep
-                 to serve requests (defaults to 1)
+                 to serve requests (defaults to 1,
+                 requires -listen)
+   -p -pidfile   specify filename for pid file
+                 (requires -listen)
+   -d -daemon    daemonize (requires -listen)
+   -M -manager   specify alternate process manager
+                 (FCGI::ProcManager sub-class)
+                 or empty string to disable
 
 =head1 DESCRIPTION
 
@@ -699,7 +755,7 @@ it under the same terms as Perl itself.
 
 =cut
 __server__
-[% startperl %] -w
+[% startperl %]
 
 BEGIN { 
     $ENV{CATALYST_ENGINE} ||= 'HTTP';
@@ -711,12 +767,13 @@ use Getopt::Long;
 use Pod::Usage;
 use FindBin;
 use lib "$FindBin::Bin/../lib";
-use [% name %];
 
+my $debug         = 0;
 my $fork          = 0;
 my $help          = 0;
 my $host          = undef;
 my $port          = 3000;
+my $keepalive     = 0;
 my $restart       = 0;
 my $restart_delay = 1;
 my $restart_regex = '\.yml$|\.yaml$|\.pm$';
@@ -724,10 +781,12 @@ my $restart_regex = '\.yml$|\.yaml$|\.pm$';
 my @argv = @ARGV;
 
 GetOptions(
+    'debug|d'           => \$debug,
     'fork'              => \$fork,
     'help|?'            => \$help,
     'host=s'            => \$host,
     'port=s'            => \$port,
+    'keepalive|k'       => \$keepalive,
     'restart|r'         => \$restart,
     'restartdelay|rd=s' => \$restart_delay,
     'restartregex|rr=s' => \$restart_regex
@@ -735,10 +794,22 @@ GetOptions(
 
 pod2usage(1) if $help;
 
+if ( $restart ) {
+    $ENV{CATALYST_ENGINE} = 'HTTP::Restarter';
+}
+if ( $debug ) {
+    $ENV{CATALYST_DEBUG} = 1;
+}
+
+# This is require instead of use so that the above environment
+# variables can be set at runtime.
+require [% name %];
+
 [% name %]->run( $port, $host, {
-    argv   => \@argv,
-    'fork' => $fork,
-    restart => $restart,
+    argv          => \@argv,
+    'fork'        => $fork,
+    keepalive     => $keepalive,
+    restart       => $restart,
     restart_delay => $restart_delay,
     restart_regex => qr/$restart_regex/
 } );
@@ -754,11 +825,13 @@ pod2usage(1) if $help;
 [% appprefix %]_server.pl [options]
 
  Options:
+   -d -debug          force debug mode
    -f -fork           handle each request in a new process
                       (defaults to false)
    -? -help           display this help and exits
       -host           host (defaults to all)
    -p -port           port (defaults to 3000)
+   -k -keepalive      enable keep-alive connections
    -r -restart        restart when files got modified
                       (defaults to false)
    -rd -restartdelay  delay between file checks
@@ -787,16 +860,14 @@ it under the same terms as Perl itself.
 
 =cut
 __test__
-[% startperl %] -w
-
-BEGIN { $ENV{CATALYST_ENGINE} ||= 'Test' }
+[% startperl %]
 
 use strict;
 use Getopt::Long;
 use Pod::Usage;
 use FindBin;
 use lib "$FindBin::Bin/../lib";
-use [% name %];
+use Catalyst::Test '[% name %]';
 
 my $help = 0;
 
@@ -804,7 +875,7 @@ GetOptions( 'help|?' => \$help );
 
 pod2usage(1) if ( $help || !$ARGV[0] );
 
-print [% name %]->run($ARGV[0])->content . "\n";
+print request($ARGV[0])->content . "\n";
 
 1;
 
@@ -844,22 +915,25 @@ it under the same terms as Perl itself.
 
 =cut
 __create__
-[% startperl %] -w
+[% startperl %]
 
 use strict;
 use Getopt::Long;
 use Pod::Usage;
 use Catalyst::Helper;
 
-my $help = 0;
-my $nonew = 0;
+my $force = 0;
+my $help  = 0;
 
-GetOptions( 'help|?' => \$help,
-           'nonew'  => \$nonew );
+GetOptions(
+    'nonew|force' => \$force,
+    'help|?'      => \$help
+ );
 
 pod2usage(1) if ( $help || !$ARGV[0] );
 
-my $helper = Catalyst::Helper->new({'.newfiles' => !$nonew});
+my $helper = Catalyst::Helper->new( { '.newfiles' => !$force } );
+
 pod2usage(1) unless $helper->mk_component( '[% name %]', @ARGV );
 
 1;
@@ -873,8 +947,8 @@ pod2usage(1) unless $helper->mk_component( '[% name %]', @ARGV );
 [% appprefix %]_create.pl [options] model|view|controller name [helper] [options]
 
  Options:
-   -help    display this help and exits
-   -nonew   don't create a .new file where a file to be created exists
+   -force    don't create a .new file where a file to be created exists
+   -help     display this help and exits
 
  Examples:
    [% appprefix %]_create.pl controller My::Controller
@@ -895,11 +969,11 @@ Create a new Catalyst Component.
 
 Existing component files are not overwritten.  If any of the component files
 to be created already exist the file will be written with a '.new' suffix.
-This behavior can be suppressed with the C<-nonew> option.
+This behavior can be suppressed with the C<-force> option.
 
 =head1 AUTHOR
 
-Sebastian Riedel, C<sri\@oook.de>
+Sebastian Riedel, C<sri@oook.de>
 
 =head1 COPYRIGHT
 
@@ -914,11 +988,11 @@ package [% class %];
 
 use strict;
 use warnings;
-use base 'Catalyst::Base';
+use base 'Catalyst::[% long_type %]';
 
 =head1 NAME
 
-[% class %] - Catalyst component
+[% class %] - Catalyst [% long_type %]
 
 =head1 SYNOPSIS
 
@@ -926,14 +1000,16 @@ See L<[% app %]>
 
 =head1 DESCRIPTION
 
-Catalyst component.
-[% IF type == 'C' %]
+Catalyst [% long_type %].
+[% IF long_type == 'Controller' %]
 =head1 METHODS
 
-=over 4
+=cut
 
-# Uncomment, modify and add new actions to fit your needs
-#=item default
+#
+# Uncomment and modify this or add new actions to fit your needs
+#
+#=head2 default
 #
 #=cut
 #
@@ -944,8 +1020,6 @@ Catalyst component.
 #    $c->response->body('[% class %] is on Catalyst!');
 #}
 
-=back
-
 [% END %]
 =head1 AUTHOR
 
@@ -960,7 +1034,7 @@ it under the same terms as Perl itself.
 
 1;
 __comptest__
-[% IF type == 'C' %]
+[% IF long_type == 'Controller' %]
 use Test::More tests => 3;
 use_ok( Catalyst::Test, '[% app %]' );
 use_ok('[% class %]');