Improved PAR support
[catagits/Catalyst-Runtime.git] / lib / Module / Install / Catalyst.pm
1 package Module::Install::Catalyst;
2
3 use strict;
4 use base 'Module::Install::Base';
5 use File::Find;
6 use FindBin;
7 use File::Copy::Recursive 'rcopy';
8 use File::Spec ();
9
10 our @IGNORE =
11   qw/Build Build.PL Changes MANIFEST META.yml Makefile.PL Makefile README
12   _build blib lib script t inc/;
13 our @CLASSES   = ();
14 our $ENGINE    = 'CGI';
15 our $CORE      = 0;
16 our $MULTIARCH = 0;
17 our $SCRIPT    = '';
18
19 =head1 NAME
20
21 Module::Install::Catalyst - Module::Install extension for Catalyst
22
23 =head1 SYNOPSIS
24
25 See L<Catalyst>
26
27 =head1 DESCRIPTION
28
29 L<Module::Install> extension for Catalyst.
30
31 =head1 METHODS
32
33 =head2 catalyst_files
34
35 =cut
36
37 sub catalyst_files {
38     my $self = shift;
39
40     chdir $FindBin::Bin;
41
42     my @files;
43     opendir CATDIR, '.';
44   CATFILES: for my $name ( readdir CATDIR ) {
45         for my $ignore (@IGNORE) {
46             next CATFILES if $name =~ /^$ignore$/;
47             next CATFILES if $name !~ /\w/;
48         }
49         push @files, $name;
50     }
51     closedir CATDIR;
52     my @path = split '::', $self->name;
53     for my $orig (@files) {
54         my $path = File::Spec->catdir( 'blib', 'lib', @path, $orig );
55         rcopy( $orig, $path );
56     }
57 }
58
59 =head2 catalyst_ignore_all(\@ignore)
60
61 =cut
62
63 sub catalyst_ignore_all {
64     my ( $self, $ignore ) = @_;
65     @IGNORE = @$ignore;
66 }
67
68 =head2 catalyst_ignore(\@ignore)
69
70 =cut
71
72 sub catalyst_ignore {
73     my ( $self, @ignore ) = @_;
74     push @IGNORE, @ignore;
75 }
76
77 =head2 catalyst_par($name)
78
79 =cut
80
81 # Workaround for a namespace conflict
82 sub catalyst_par { Catalyst::Module::Install::_catalyst_par(@_) }
83
84 =head2 catalyst_par_core($core)
85
86 =cut
87
88 sub catalyst_par_core {
89     my ( $self, $core ) = @_;
90     $core ? ( $CORE = $core ) : $core++;
91 }
92
93 =head2 catalyst_par_classes(@clases)
94
95 =cut
96
97 sub catalyst_par_classes {
98     my ( $self, @classes ) = @_;
99     push @CLASSES, @classes;
100 }
101
102 =head2 catalyst_par_engine($engine)
103
104 =cut
105
106 sub catalyst_par_engine {
107     my ( $self, $engine ) = @_;
108     $ENGINE = $engine;
109 }
110
111 =head2 catalyst_par_multiarch($multiarch)
112
113 =cut
114
115 sub catalyst_par_multiarch {
116     my ( $self, $multiarch ) = @_;
117     $multiarch ? ( $MULTIARCH = $multiarch ) : $multiarch++;
118 }
119
120 =head2 catalyst_par_script($script)
121
122 =cut
123
124 sub catalyst_par_script {
125     my ( $self, $script ) = @_;
126     $SCRIPT = $script;
127 }
128
129 package Catalyst::Module::Install;
130
131 use strict;
132 use FindBin;
133 use File::Copy::Recursive 'rmove';
134 use File::Spec ();
135
136 sub _catalyst_par {
137     my ( $self, $par ) = @_;
138
139     my $name = $self->name;
140     $name =~ s/::/_/g;
141     $name = lc $name;
142     $par ||= "$name.par";
143     my $engine = $Module::Install::Catalyst::ENGINE || 'CGI';
144     my $script = $Module::Install::Catalyst::SCRIPT || "$name\_cgi.pl";
145
146     # Check for PAR
147     eval "use PAR ()";
148     die "Please install PAR\n" if $@;
149     eval "use PAR::Packer ()";
150     die "Please install PAR::Packer\n" if $@;
151     eval "use App::Packer::PAR ()";
152     die "Please install App::Packer::PAR\n" if $@;
153     eval "use Module::ScanDeps ()";
154     die "Please install Module::ScanDeps\n" if $@;
155
156     my $root = $FindBin::Bin;
157     my $path = File::Spec->catfile( 'blib', 'lib', split( '::', $self->name ) );
158     $path .= '.pm';
159     unless ( -f $path ) {
160         print qq/Not writing PAR, "$path" doesn't exist\n/;
161         return 0;
162     }
163     print qq/Writing PAR "$par"\n/;
164     chdir File::Spec->catdir( $root, 'blib' );
165
166     my $par_pl = 'par.pl';
167     unlink $par_pl;
168
169     my $version = $Catalyst::VERSION;
170     my $class   = $self->name;
171
172     my $script_file    = IO::File->new("< $script");
173     my $script_content = do { local $/; <$script_file> };
174
175     my $classes = '';
176     $classes .= "    require $_;\n" for @Catalyst::Module::Install::CLASSES;
177     my $tmp_file = IO::File->new("> $par_pl ");
178     print $tmp_file <<"EOF";
179 require lib;
180 if (\$0 !~ /par.pl\.\\w+\$/) {
181 $script_content
182 }
183 else {
184     import lib 'lib';
185     \$ENV{CATALYST_ENGINE} = '$engine';
186     require $class;
187     import $class;
188     require Catalyst::Helper;
189     require Catalyst::Test;
190     require Catalyst::Engine::HTTP;
191     require Catalyst::Engine::CGI;
192     require Catalyst::Controller;
193     require Catalyst::Model;
194     require Catalyst::View;
195     $classes
196 }
197 EOF
198     $tmp_file->close;
199
200     # Create package
201     local $SIG{__WARN__} = sub { };
202     open my $olderr, '>&STDERR';
203     open STDERR, '>', File::Spec->devnull;
204     my %opt = (
205         'x' => 1,
206         'n' => 0,
207         'o' => $par,
208         'a' => [ grep( !/par.pl/, glob '.' ) ],
209         'p' => 1,
210         'B' => $Module::Install::Catalyst::CORE,
211         'm' => $Module::Install::Catalyst::MULTIARCH
212     );
213     App::Packer::PAR->new(
214         frontend  => 'Module::ScanDeps',
215         backend   => 'PAR::Packer',
216         frontopts => \%opt,
217         backopts  => \%opt,
218         args      => ['par.pl'],
219     )->go;
220
221     open STDERR, '>&', $olderr;
222
223     unlink $par_pl;
224     chdir $root;
225     rmove( File::Spec->catfile( 'blib', $par ), $par );
226     return 1;
227 }
228
229 =head1 AUTHOR
230
231 Sebastian Riedel, C<sri@oook.de>
232
233 =head1 LICENSE
234
235 This library is free software, you can redistribute it and/or modify it under
236 the same terms as Perl itself.
237
238 =cut
239
240 1;