Added POD description for some methods.
[catagits/Catalyst-Devel.git] / lib / Module / Install / Catalyst.pm
1 package Module::Install::Catalyst;
2
3 use strict;
4
5 our @ISA;
6 require Module::Install::Base;
7 @ISA = qw/Module::Install::Base/;
8
9 use File::Find;
10 use FindBin;
11 use File::Copy::Recursive 'rcopy';
12 use File::Spec ();
13
14 my $SAFETY = 0;
15
16 our @IGNORE =
17   qw/Build Build.PL Changes MANIFEST META.yml Makefile.PL Makefile README
18   _build blib lib script t inc .*\.svn \.git _darcs \.bzr \.hg
19   debian build-stamp install-stamp configure-stamp/;
20 our @CLASSES   = ();
21 our $ENGINE    = 'CGI';
22 our $CORE      = 0;
23 our $MULTIARCH = 0;
24 our $SCRIPT    = '';
25 our $USAGE     = '';
26
27 =head1 NAME
28
29   Module::Install::Catalyst - Module::Install extension for Catalyst
30   
31 =head1 SYNOPSIS
32   
33   use inc::Module::Install;
34   
35   name 'MyApp';
36   all_from 'lib/MyApp.pm';
37   
38   requires 'Catalyst::Runtime' => '5.7014';
39   
40   catalyst_ignore('.*temp');
41   catalyst_ignore('.*tmp');
42   catalyst;
43   WriteAll;
44
45 =head1 DESCRIPTION
46
47 L<Module::Install> extension for Catalyst.
48
49 =head1 METHODS
50
51 =head2 catalyst
52
53 Calls L<catalyst_files> and L<catalyst_par>. Should be the last catalyst*
54 command called in C<Makefile.PL>.
55
56 =cut
57
58 sub catalyst {
59     my $self = shift;
60     print <<EOF;
61 *** Module::Install::Catalyst
62 EOF
63     $self->catalyst_files;
64     $self->catalyst_par;
65     print <<EOF;
66 *** Module::Install::Catalyst finished.
67 EOF
68 }
69
70 =head2 catalyst_files
71
72 Collect a list of all files a Catalyst application consists of and copy it  
73 inside the blib/lib/ directory. Files and directories that match the modules 
74 ignore list are excluded (see L<catalyst_ignore> and L<catalyst_ignore_all>).
75
76 =cut
77
78 sub catalyst_files {
79     my $self = shift;
80
81     chdir $FindBin::Bin;
82
83     my @files;
84     opendir CATDIR, '.';
85   CATFILES: for my $name ( readdir CATDIR ) {
86         for my $ignore (@IGNORE) {
87             next CATFILES if $name =~ /^$ignore$/;
88             next CATFILES if $name !~ /\w/;
89         }
90         push @files, $name;
91     }
92     closedir CATDIR;
93     my @path = split '-', $self->name;
94     for my $orig (@files) {
95         my $path = File::Spec->catdir( 'blib', 'lib', @path, $orig );
96         rcopy( $orig, $path );
97     }
98 }
99
100 =head2 catalyst_ignore_all(\@ignore)
101
102 This function replaces the built-in default ignore list with the given list.
103
104 =cut
105
106 sub catalyst_ignore_all {
107     my ( $self, $ignore ) = @_;
108     @IGNORE = @$ignore;
109 }
110
111 =head2 catalyst_ignore(\@ignore)
112
113 Add a regexp to the list of ignored patterns. Can be called multiple times.
114
115 =cut
116
117 sub catalyst_ignore {
118     my ( $self, @ignore ) = @_;
119     push @IGNORE, @ignore;
120 }
121
122 =head2 catalyst_par($name)
123
124 =cut
125
126 # Workaround for a namespace conflict
127 sub catalyst_par {
128     my ( $self, $par ) = @_;
129     $par ||= '';
130     return if $SAFETY;
131     $SAFETY++;
132     my $name  = $self->name;
133     my $usage = $USAGE;
134     $usage =~ s/"/\\"/g;
135     my $class_string = join "', '", @CLASSES;
136     $class_string = "'$class_string'" if $class_string;
137     $self->postamble(<<EOF);
138 catalyst_par :: all
139 \t\$(NOECHO) \$(PERL) -Ilib -Minc::Module::Install -MModule::Install::Catalyst -e"Catalyst::Module::Install::_catalyst_par( '$par', '$name', { CLASSES => [$class_string], CORE => $CORE, ENGINE => '$ENGINE', MULTIARCH => $MULTIARCH, SCRIPT => '$SCRIPT', USAGE => q#$usage# } )"
140 EOF
141     print <<EOF;
142 Please run "make catalyst_par" to create the PAR package!
143 EOF
144 }
145
146 =head2 catalyst_par_core($core)
147
148 =cut
149
150 sub catalyst_par_core {
151     my ( $self, $core ) = @_;
152     $core ? ( $CORE = $core ) : $CORE++;
153 }
154
155 =head2 catalyst_par_classes(@clases)
156
157 =cut
158
159 sub catalyst_par_classes {
160     my ( $self, @classes ) = @_;
161     push @CLASSES, @classes;
162 }
163
164 =head2 catalyst_par_engine($engine)
165
166 =cut
167
168 sub catalyst_par_engine {
169     my ( $self, $engine ) = @_;
170     $ENGINE = $engine;
171 }
172
173 =head2 catalyst_par_multiarch($multiarch)
174
175 =cut
176
177 sub catalyst_par_multiarch {
178     my ( $self, $multiarch ) = @_;
179     $multiarch ? ( $MULTIARCH = $multiarch ) : $MULTIARCH++;
180 }
181
182 =head2 catalyst_par_script($script)
183
184 =cut
185
186 sub catalyst_par_script {
187     my ( $self, $script ) = @_;
188     $SCRIPT = $script;
189 }
190
191 =head2 catalyst_par_usage($usage)
192
193 =cut
194
195 sub catalyst_par_usage {
196     my ( $self, $usage ) = @_;
197     $USAGE = $usage;
198 }
199
200 package Catalyst::Module::Install;
201
202 use strict;
203 use FindBin;
204 use File::Copy::Recursive 'rmove';
205 use File::Spec ();
206
207 sub _catalyst_par {
208     my ( $par, $class_name, $opts ) = @_;
209
210     my $ENGINE    = $opts->{ENGINE};
211     my $CLASSES   = $opts->{CLASSES} || [];
212     my $USAGE     = $opts->{USAGE};
213     my $SCRIPT    = $opts->{SCRIPT};
214     my $MULTIARCH = $opts->{MULTIARCH};
215     my $CORE      = $opts->{CORE};
216
217     my $name = $class_name;
218     $name =~ s/::/_/g;
219     $name = lc $name;
220     $par ||= "$name.par";
221     my $engine = $ENGINE || 'CGI';
222
223     # Check for PAR
224     eval "use PAR ()";
225     die "Please install PAR\n" if $@;
226     eval "use PAR::Packer ()";
227     die "Please install PAR::Packer\n" if $@;
228     eval "use App::Packer::PAR ()";
229     die "Please install App::Packer::PAR\n" if $@;
230     eval "use Module::ScanDeps ()";
231     die "Please install Module::ScanDeps\n" if $@;
232
233     my $root = $FindBin::Bin;
234     $class_name =~ s/-/::/g;
235     my $path = File::Spec->catfile( 'blib', 'lib', split( '::', $class_name ) );
236     $path .= '.pm';
237     unless ( -f $path ) {
238         print qq/Not writing PAR, "$path" doesn't exist\n/;
239         return 0;
240     }
241     print qq/Writing PAR "$par"\n/;
242     chdir File::Spec->catdir( $root, 'blib' );
243
244     my $par_pl = 'par.pl';
245     unlink $par_pl;
246
247     my $version = $Catalyst::VERSION;
248     my $class   = $class_name;
249
250     my $classes = '';
251     $classes .= "    require $_;\n" for @$CLASSES;
252
253     unlink $par_pl;
254
255     my $usage = $USAGE || <<"EOF";
256 Usage:
257     [parl] $name\[.par] [script] [arguments]
258
259   Examples:
260     parl $name.par $name\_server.pl -r
261     myapp $name\_cgi.pl
262 EOF
263
264     my $script   = $SCRIPT;
265     my $tmp_file = IO::File->new("> $par_pl ");
266     print $tmp_file <<"EOF";
267 if ( \$ENV{PAR_PROGNAME} ) {
268     my \$zip = \$PAR::LibCache{\$ENV{PAR_PROGNAME}}
269         || Archive::Zip->new(__FILE__);
270     my \$script = '$script';
271     \$ARGV[0] ||= \$script if \$script;
272     if ( ( \@ARGV == 0 ) || ( \$ARGV[0] eq '-h' ) || ( \$ARGV[0] eq '-help' )) {
273         my \@members = \$zip->membersMatching('.*script/.*\.pl');
274         my \$list = "  Available scripts:\\n";
275         for my \$member ( \@members ) {
276             my \$name = \$member->fileName;
277             \$name =~ /(\\w+\\.pl)\$/;
278             \$name = \$1;
279             next if \$name =~ /^main\.pl\$/;
280             next if \$name =~ /^par\.pl\$/;
281             \$list .= "    \$name\\n";
282         }
283         die <<"END";
284 $usage
285 \$list
286 END
287     }
288     my \$file = shift \@ARGV;
289     \$file =~ s/^.*[\\/\\\\]//;
290     \$file =~ s/\\.[^.]*\$//i;
291     my \$member = eval { \$zip->memberNamed("./script/\$file.pl") };
292     die qq/Can't open perl script "\$file"\n/ unless \$member;
293     PAR::_run_member( \$member, 1 );
294 }
295 else {
296     require lib;
297     import lib 'lib';
298     \$ENV{CATALYST_ENGINE} = '$engine';
299     require $class;
300     import $class;
301     require Catalyst::Helper;
302     require Catalyst::Test;
303     require Catalyst::Engine::HTTP;
304     require Catalyst::Engine::CGI;
305     require Catalyst::Controller;
306     require Catalyst::Model;
307     require Catalyst::View;
308     require Getopt::Long;
309     require Pod::Usage;
310     require Pod::Text;
311     $classes
312 }
313 EOF
314     $tmp_file->close;
315
316     # Create package
317     local $SIG{__WARN__} = sub { };
318     open my $olderr, '>&STDERR';
319     open STDERR, '>', File::Spec->devnull;
320     my %opt = (
321         'x' => 1,
322         'n' => 0,
323         'o' => $par,
324         'a' => [ grep( !/par.pl/, glob '.' ) ],
325         'p' => 1,
326         'B' => $CORE,
327         'm' => $MULTIARCH
328     );
329     App::Packer::PAR->new(
330         frontend  => 'Module::ScanDeps',
331         backend   => 'PAR::Packer',
332         frontopts => \%opt,
333         backopts  => \%opt,
334         args      => ['par.pl'],
335     )->go;
336
337     open STDERR, '>&', $olderr;
338
339     unlink $par_pl;
340     chdir $root;
341     rmove( File::Spec->catfile( 'blib', $par ), $par );
342     return 1;
343 }
344
345 =head1 AUTHORS
346
347 Catalyst Contributors, see Catalyst.pm
348
349 =head1 LICENSE
350
351 This library is free software. You can redistribute it and/or modify it under
352 the same terms as Perl itself.
353
354 =cut
355
356 1;