File Coverage

blib/lib/Apache/Bootstrap.pm
Criterion Covered Total %
statement 30 115 26.0
branch 8 62 12.9
condition 5 50 10.0
subroutine 6 12 50.0
pod 6 6 100.0
total 55 245 22.4


line stmt bran cond sub pod time code
1             package Apache::Bootstrap;
2              
3 1     1   25542 use warnings;
  1         2  
  1         26  
4 1     1   5 use strict;
  1         2  
  1         48  
5              
6             =head1 NAME
7              
8             Apache::Bootstrap - Bootstraps dual life mod_perl and mod_perl2 Apache modules
9              
10             =cut
11              
12             our $VERSION = '0.07';
13              
14 1     1   4 use constant MIN_MP2_VER => '1.99022'; # mp2 renaming
  1         5  
  1         505  
15              
16             =head1 SYNOPSIS
17              
18             In your Makefile.PL
19              
20             use Apache::Bootstrap 0.07;
21              
22             my $bootstrap;
23              
24             BEGIN {
25             # check to make sure we have mod_perl 1 installed
26             $bootstrap = Apache::Bootstrap->new({ mod_perl => 0 });
27              
28             # or check for mod_perl 2
29             $bootstrap = Apache::Bootstrap->new({ mod_perl2 => '1.99022' });
30             }
31              
32             # check for Apache::Test, return the installed version if exists
33             my $has_apache_test = $bootstrap->check_for_apache_test();
34              
35             # see if mod_perl2 is installed (useful when both mp1 and mp2 are installed)
36             my $mp_generation = $bootstrap->satisfy_mp_generation( 2 );
37              
38             unless ($mp_generation) {
39              
40             # no mod_perl2? look for mod_perl 1
41             $mp_generation = $bootstrap->satisfy_mp_generation( 1 );
42             }
43              
44             # any mod_perl version will do
45             $mp_generation = Apache::Bootstrap->satisfy_mp_generation();
46             unless ( $mp_generation ) {
47             warn( 'No mod_perl installation was found' )
48             } else {
49             warn( "mod_perl generation $mp_generation was found" );
50             }
51              
52             # write the Makefile using a mod_perl version dependent build subsystem
53             $bootstrap->WriteMakefile( %maker_options );
54              
55             =head1 DESCRIPTION
56              
57             Writing modules for mod_perl that work under both mod_perl and mod_perl2 is not fun.
58              
59             This module is here to make that endeavour less painful. mod_perl2 is great, but
60             a lot of users are still using mod_perl. Migrating to mod_perl2 while maintaining
61             mod_perl compatibility isn't easy, and this module is here to make that transition
62             as painless as possible.
63              
64             =head1 METHODS
65              
66             =head2 new()
67              
68             # try to find these versions of mod_perl, die if none are found
69             $bootstrap = Apache::Bootstrap->new({
70             mod_perl2 => 1.99022, # after mp2 renaming
71             mod_perl => 0, # any verison of mp1
72             });
73              
74             These code checks to see if either mp1 or mp2 versions are present.
75             One successful version check means that it returns a valid object.
76              
77             =cut
78              
79             sub new {
80 2     2 1 3399 my ( $class, $args ) = @_;
81              
82 2 50 33     21 die 'perldoc Apache::Bootstrap'
      66        
      33        
83             unless $args
84             && ref $args eq 'HASH'
85             && ( defined $args->{mod_perl} or defined $args->{mod_perl2} );
86              
87 2         2 my %self;
88 2 100       6 if ( defined $args->{mod_perl} ) {
89              
90             # delete mp2 from inc first, note that we don't delete mod_perl2.pm
91 1         2 delete $INC{'mod_perl.pm'};
92              
93             # look for mp1
94 1         1 eval { require mod_perl };
  1         323  
95 1 50 0     5 if ($@) {
    0          
96 1         34 warn("mod_perl not present, cannot bootstrap mp1");
97              
98             }
99             elsif (( $mod_perl::VERSION < $args->{mod_perl} )
100             or ( $mod_perl::VERSION >= MIN_MP2_VER ) )
101             {
102              
103 0         0 warn(sprintf( 'mod_perl version %s not found, we have %s',
104             $args->{mod_perl}, $mod_perl::VERSION ));
105              
106             }
107             else {
108              
109             # store the version we have
110 0         0 $self{mod_perl} = $mod_perl::VERSION;
111             }
112              
113             }
114              
115 2 100       6 if ( defined $args->{mod_perl2} ) {
116              
117             # look for mp2
118 1         1 eval { require mod_perl2 };
  1         356  
119              
120 1 50       6 if ($@) {
    0          
121 1         24 warn("mod_perl2 not present, cannot bootstrap mp2");
122              
123             }
124             elsif ( $mod_perl2::VERSION < $args->{mod_perl2} ) {
125              
126 0         0 warn(sprintf( "mod_perl2 version %s not found, we have %s",
127             $args->{mod_perl2}, $mod_perl2::VERSION ));
128              
129             }
130             else {
131              
132             # store the version we have
133 0         0 $self{mod_perl2} = $mod_perl2::VERSION;
134             }
135              
136             }
137              
138             # make sure that we have at least one mod_perl version present
139 2 50 33     19 die "no versions of mod_perl could be found matching your constraints\n"
140             unless ( defined $self{mod_perl} or defined $self{mod_perl2} );
141              
142 0           bless \%self, $class;
143              
144 0           return \%self;
145             }
146              
147             =head2 mp_prereqs()
148              
149             returns the prerequisites for mod_perl versions in a hash reference
150              
151             =cut
152              
153             sub mp_prereqs {
154 0     0 1   my $self = shift;
155             return {
156 0           map { $_ => $self->{$_} }
  0            
157 0           grep { /^mod_perl2?$/ } keys %{$self}
  0            
158             };
159             }
160              
161             =head2 check_for_apache_test()
162              
163             $apache_test_version = Apache::Bootstrap->check_for_apache_test;
164              
165             Returns the version of Apache::Test installed. Returns undefined if
166             Apache::Test is not installed.
167              
168             =cut
169              
170             sub check_for_apache_test {
171 0     0 1   my ( $self, $at_min_ver ) = @_;
172              
173 0 0         return unless eval {
174 0           require Apache::Test;
175 0 0 0       if ( $Apache::Test::VERSION < ( $at_min_ver || 0 ) ) {
176 0           warn "Apache::Test version is "
177             . $Apache::Test::VERSION
178             . ", minimum version required is $at_min_ver"
179             . ", tests will be skipped\n";
180 0           die;
181             }
182 0           require Apache::TestMM;
183 0           require Apache::TestRunPerl;
184 0           1;
185             };
186              
187 0           Apache::TestMM::filter_args();
188              
189 1     1   5 no warnings; # silence '@Apache::TestMM::Argv used only once' warning
  1         1  
  1         622  
190 0           my %args = @Apache::TestMM::Argv;
191              
192             return
193             unless (
194             (
195 0 0 0       Apache::TestConfig->can('custom_config_path')
      0        
      0        
      0        
      0        
196             and -f Apache::TestConfig->custom_config_path()
197             )
198             or $args{apxs}
199             or $args{httpd}
200             or $ENV{APACHE_TEST_HTTPD}
201             or $ENV{APACHE_TEST_APXS}
202             );
203              
204 0           Apache::TestRunPerl->generate_script();
205              
206 0           return $Apache::Test::VERSION;
207             }
208              
209             =head2 satisfy_mp_generation()
210              
211             # see if mod_perl2 is installed
212             my $mp_generation = $bootstrap->satisfy_mp_generation( 2 );
213              
214             unless ($mp_generation) {
215              
216             # no mod_perl2? look for mod_perl 1
217             $mp_generation = $bootstrap->satisfy_mp_generation( 1 );
218             }
219              
220             # any mod_perl version will do, check for mp2 first
221             $mp_generation = $bootstrap->satisfy_mp_generation();
222             unless ( $mp_generation ) {
223             warn( 'No mod_perl installation was found' )
224             } else {
225             warn( "mod_perl generation $mp_generation was found" );
226             }
227              
228              
229             =cut
230              
231             sub satisfy_mp_generation {
232 0     0 1   my ( $self, $wanted ) = @_;
233              
234 0   0       $wanted ||= $self->_wanted_mp_generation();
235              
236 0 0 0       unless ( $wanted == 1 || $wanted == 2 ) {
237 0           die "don't know anything about mod_perl generation: $wanted\n"
238             . "currently supporting only generations 1 and 2";
239             }
240              
241 0           my $selected = 0;
242              
243 0 0         if ( $wanted == 1 ) {
    0          
244              
245 0           eval { require mod_perl };
  0            
246 0 0         if ($@) {
247 0           warn("require mod_perl failed");
248 0           return;
249             }
250              
251 0           $selected = 1;
252             }
253             elsif ( $wanted == 2 ) {
254              
255 0           eval { require mod_perl2 };
  0            
256 0 0         if ($@) {
257 0           warn("require mod_perl2 failed");
258 0           return;
259             }
260              
261 0           $selected = 2;
262             }
263             else {
264              
265             # try mp2 first
266 0           eval { require mod_perl2 };
  0            
267 0 0         if ($@) {
268 0           warn("require mod_perl2 failed");
269              
270 0           eval { require mod_perl };
  0            
271 0 0         if ($@) {
272 0           warn("require mod_perl failed");
273 0           return;
274             }
275             }
276              
277 0 0         $selected = $mod_perl::VERSION >= MIN_MP2_VER ? 2 : 1;
278             }
279              
280             # make sure we have the needed build modules
281 0 0         my $build_pkg =
282             ( $selected == 2 ) ? 'ModPerl::BuildMM' : 'ExtUtils::MakeMaker';
283 0           eval "require $build_pkg";
284 0 0         die "could not require package $build_pkg: $@" if $@;
285              
286 0           $self->{maker} = $build_pkg;
287              
288 0           return $self->{mp_gen} = $selected;
289             }
290              
291             # _wanted_mp_generation()
292             #
293             # the function looks at %ENV and Makefile.PL option to figure out
294             # whether a specific mod_perl generation was requested.
295             # It uses the following logic:
296             # via options:
297             # perl Makefile.PL MOD_PERL=2
298             # or via %ENV:
299             # env MOD_PERL=1 perl Makefile.PL
300             #
301             # return value is:
302             # 1 or 2 if the specification was found (mp 1 and mp 2 respectively)
303             # 0 otherwise
304              
305             # Currently the logic for determining the mod_perl generation
306             # is as follows.
307              
308             # If a specific generation was passed as an argument,
309             # if satisfied
310             # return the same generation
311             # else
312             # die
313             # else @ARGV and %ENV will be checked for specific orders
314             # if the specification will be found
315             # if satisfied
316             # return the specified generation
317             # else
318             # die
319             # else if any mp generation is found
320             # return it
321             # else
322             # die
323              
324             sub _wanted_mp_generation {
325 0     0     my $self = shift;
326              
327             # check if we have a command line specification
328             # flag: 0: unknown, 1: mp1, 2: mp2
329 0           my $flag = 0;
330 0           foreach my $key (@ARGV) {
331 0 0         if ( $key =~ /^MOD_PERL=([12])$/ ) {
332 0           $flag = $1;
333             }
334             }
335              
336             # check %ENV
337 0 0         my $env = exists $ENV{MOD_PERL} ? $ENV{MOD_PERL} : 0;
338              
339             # check for contradicting requirements
340 0 0 0       if ( $env && $flag && $flag != $env ) {
      0        
341 0           warn <
342             Can\'t decide which mod_perl version should be used, since you have
343             supplied contradicting requirements:
344             enviroment variable MOD_PERL=$env
345             Makefile.PL option MOD_PERL=$flag
346             EOF
347 0           die;
348             }
349              
350 0           my $wanted = 0;
351 0 0 0       $wanted = 2 if $env == 2 || $flag == 2;
352 0 0 0       $wanted = 1 if $env == 1 || $flag == 1;
353              
354 0 0         unless ($wanted) {
355              
356             # if still unknown try to require mod_perl2.pm
357 0           eval { require mod_perl2 };
  0            
358 0 0         if ($@) {
359              
360             # if we don't have mp2, check for mp1
361 0 0         eval { require mod_perl } if ($@);
  0            
362 0 0         unless ($@) {
363 0           $wanted = 1;
364             }
365             }
366             else {
367 0           $wanted = 2;
368             }
369             }
370              
371 0           return $wanted;
372             }
373              
374             =head2 apache_major_version()
375              
376             $apache_major_version = $bootstrap->apache_major_version;
377              
378             The major version number of the target apache install
379              
380             =cut
381              
382             sub apache_major_version {
383 0 0   0 1   return ( shift->{mp_gen} == 1 ) ? 'Apache' : 'Apache2';
384             }
385              
386             =head2 WriteMakefile()
387              
388             $bootstrap->write_makefile( %makefile_options );
389              
390             Writes the makefile using the appropriate make engine depending on what
391             mod_perl version is in use. Same API as ExtUtils::MakeMaker or ModPerl::BuildMM
392              
393             =cut
394              
395             sub WriteMakefile {
396 0     0 1   my ( $self, %maker_opts ) = @_;
397              
398             # write the makefile
399 0           my $sub = "$self->{maker}\:\:WriteMakefile";
400             {
401 1     1   6 no strict 'refs';
  1         1  
  1         59  
  0            
402 0           $sub->(%maker_opts);
403             }
404             }
405              
406             =head1 AUTHOR
407              
408             Fred Moyer
409              
410             The mod_perl development team C<> and numerous contributors.
411              
412             This code was lifted from Apache::SizeLimit in an effort to make it useful to
413             other modules such as Apache::Reload, Apache::Dispatch, any dual life Apache module.
414              
415             =head1 BUGS
416              
417             Please report bugs to the mod_perl development mailing list C<>
418              
419             =cut
420              
421             1;