Commit | Line | Data |
---|---|---|
bb4e9162 YST |
1 | package Module::Build::Base; |
2 | ||
3 | use strict; | |
4 | BEGIN { require 5.00503 } | |
dc8021d3 SP |
5 | |
6 | use Carp; | |
bb4e9162 YST |
7 | use Config; |
8 | use File::Copy (); | |
9 | use File::Find (); | |
10 | use File::Path (); | |
11 | use File::Basename (); | |
12 | use File::Spec 0.82 (); | |
13 | use File::Compare (); | |
14 | use Data::Dumper (); | |
15 | use IO::File (); | |
16 | use Text::ParseWords (); | |
bb4e9162 YST |
17 | |
18 | use Module::Build::ModuleInfo; | |
19 | use Module::Build::Notes; | |
77e96e88 | 20 | use Module::Build::Config; |
bb4e9162 YST |
21 | |
22 | ||
23 | #################### Constructors ########################### | |
24 | sub new { | |
25 | my $self = shift()->_construct(@_); | |
26 | ||
27 | $self->{invoked_action} = $self->{action} ||= 'Build_PL'; | |
28 | $self->cull_args(@ARGV); | |
29 | ||
30 | die "Too early to specify a build action '$self->{action}'. Do 'Build $self->{action}' instead.\n" | |
31 | if $self->{action} && $self->{action} ne 'Build_PL'; | |
32 | ||
33 | $self->dist_name; | |
34 | $self->dist_version; | |
35 | ||
36 | $self->check_manifest; | |
37 | $self->check_prereq; | |
38 | $self->check_autofeatures; | |
39 | ||
40 | $self->_set_install_paths; | |
41 | $self->_find_nested_builds; | |
42 | ||
43 | return $self; | |
44 | } | |
45 | ||
46 | sub resume { | |
47 | my $package = shift; | |
48 | my $self = $package->_construct(@_); | |
49 | $self->read_config; | |
50 | ||
51 | # If someone called Module::Build->current() or | |
52 | # Module::Build->new_from_context() and the correct class to use is | |
53 | # actually a *subclass* of Module::Build, we may need to load that | |
54 | # subclass here and re-delegate the resume() method to it. | |
55 | unless ( UNIVERSAL::isa($package, $self->build_class) ) { | |
56 | my $build_class = $self->build_class; | |
57 | my $config_dir = $self->config_dir || '_build'; | |
58 | my $build_lib = File::Spec->catdir( $config_dir, 'lib' ); | |
59 | unshift( @INC, $build_lib ); | |
60 | unless ( $build_class->can('new') ) { | |
61 | eval "require $build_class; 1" or die "Failed to re-load '$build_class': $@"; | |
62 | } | |
63 | return $build_class->resume(@_); | |
64 | } | |
65 | ||
66 | unless ($self->_perl_is_same($self->{properties}{perl})) { | |
67 | my $perl = $self->find_perl_interpreter; | |
68 | $self->log_warn(" * WARNING: Configuration was initially created with '$self->{properties}{perl}',\n". | |
69 | " but we are now using '$perl'.\n"); | |
70 | } | |
71 | ||
bb4e9162 | 72 | $self->cull_args(@ARGV); |
0ec9ad96 SP |
73 | |
74 | unless ($self->allow_mb_mismatch) { | |
75 | my $mb_version = $Module::Build::VERSION; | |
76 | die(" * ERROR: Configuration was initially created with Module::Build version '$self->{properties}{mb_version}',\n". | |
7253302f SP |
77 | " but we are now using version '$mb_version'. Please re-run the Build.PL or Makefile.PL script,\n". |
78 | " or use --allow_mb_mismatch 1 to skip this version check.\n") | |
0ec9ad96 SP |
79 | if $mb_version ne $self->{properties}{mb_version}; |
80 | } | |
81 | ||
bb4e9162 YST |
82 | $self->{invoked_action} = $self->{action} ||= 'build'; |
83 | ||
84 | return $self; | |
85 | } | |
86 | ||
87 | sub new_from_context { | |
88 | my ($package, %args) = @_; | |
89 | ||
90 | # XXX Read the META.yml and see whether we need to run the Build.PL? | |
91 | ||
92 | # Run the Build.PL. We use do() rather than run_perl_script() so | |
93 | # that it runs in this process rather than a subprocess, because we | |
94 | # need to make sure that the environment is the same during Build.PL | |
95 | # as it is during resume() (and thereafter). | |
96 | { | |
97 | local @ARGV = $package->unparse_args(\%args); | |
7253302f | 98 | do './Build.PL'; |
bb4e9162 YST |
99 | die $@ if $@; |
100 | } | |
101 | return $package->resume; | |
102 | } | |
103 | ||
104 | sub current { | |
105 | # hmm, wonder what the right thing to do here is | |
106 | local @ARGV; | |
107 | return shift()->resume; | |
108 | } | |
109 | ||
110 | sub _construct { | |
111 | my ($package, %input) = @_; | |
112 | ||
113 | my $args = delete $input{args} || {}; | |
114 | my $config = delete $input{config} || {}; | |
115 | ||
116 | my $self = bless { | |
117 | args => {%$args}, | |
77e96e88 | 118 | config => Module::Build::Config->new(values => $config), |
bb4e9162 YST |
119 | properties => { |
120 | base_dir => $package->cwd, | |
121 | mb_version => $Module::Build::VERSION, | |
122 | %input, | |
123 | }, | |
124 | phash => {}, | |
125 | }, $package; | |
126 | ||
127 | $self->_set_defaults; | |
77e96e88 | 128 | my ($p, $ph) = ($self->{properties}, $self->{phash}); |
bb4e9162 YST |
129 | |
130 | foreach (qw(notes config_data features runtime_params cleanup auto_features)) { | |
131 | my $file = File::Spec->catfile($self->config_dir, $_); | |
132 | $ph->{$_} = Module::Build::Notes->new(file => $file); | |
133 | $ph->{$_}->restore if -e $file; | |
134 | if (exists $p->{$_}) { | |
135 | my $vals = delete $p->{$_}; | |
136 | while (my ($k, $v) = each %$vals) { | |
137 | $self->$_($k, $v); | |
138 | } | |
139 | } | |
140 | } | |
141 | ||
142 | # The following warning could be unnecessary if the user is running | |
143 | # an embedded perl, but there aren't too many of those around, and | |
144 | # embedded perls aren't usually used to install modules, and the | |
145 | # installation process sometimes needs to run external scripts | |
146 | # (e.g. to run tests). | |
147 | $p->{perl} = $self->find_perl_interpreter | |
148 | or $self->log_warn("Warning: Can't locate your perl binary"); | |
149 | ||
150 | my $blibdir = sub { File::Spec->catdir($p->{blib}, @_) }; | |
151 | $p->{bindoc_dirs} ||= [ $blibdir->("script") ]; | |
152 | $p->{libdoc_dirs} ||= [ $blibdir->("lib"), $blibdir->("arch") ]; | |
153 | ||
154 | $p->{dist_author} = [ $p->{dist_author} ] if defined $p->{dist_author} and not ref $p->{dist_author}; | |
155 | ||
156 | # Synonyms | |
157 | $p->{requires} = delete $p->{prereq} if defined $p->{prereq}; | |
158 | $p->{script_files} = delete $p->{scripts} if defined $p->{scripts}; | |
159 | ||
160 | # Convert to arrays | |
161 | for ('extra_compiler_flags', 'extra_linker_flags') { | |
162 | $p->{$_} = [ $self->split_like_shell($p->{$_}) ] if exists $p->{$_}; | |
163 | } | |
164 | ||
165 | $self->add_to_cleanup( @{delete $p->{add_to_cleanup}} ) | |
166 | if $p->{add_to_cleanup}; | |
167 | ||
168 | return $self; | |
169 | } | |
170 | ||
171 | ################## End constructors ######################### | |
172 | ||
173 | sub log_info { print @_ unless shift()->quiet } | |
174 | sub log_verbose { shift()->log_info(@_) if $_[0]->verbose } | |
175 | sub log_warn { | |
176 | # Try to make our call stack invisible | |
177 | shift; | |
178 | if (@_ and $_[-1] !~ /\n$/) { | |
179 | my (undef, $file, $line) = caller(); | |
180 | warn @_, " at $file line $line.\n"; | |
181 | } else { | |
182 | warn @_; | |
183 | } | |
184 | } | |
185 | ||
186 | ||
187 | sub _set_install_paths { | |
188 | my $self = shift; | |
77e96e88 | 189 | my $c = $self->{config}; |
bb4e9162 YST |
190 | my $p = $self->{properties}; |
191 | ||
77e96e88 RGS |
192 | my @libstyle = $c->get('installstyle') ? |
193 | File::Spec->splitdir($c->get('installstyle')) : qw(lib perl5); | |
194 | my $arch = $c->get('archname'); | |
195 | my $version = $c->get('version'); | |
bb4e9162 | 196 | |
77e96e88 RGS |
197 | my $bindoc = $c->get('installman1dir') || undef; |
198 | my $libdoc = $c->get('installman3dir') || undef; | |
bb4e9162 | 199 | |
77e96e88 RGS |
200 | my $binhtml = $c->get('installhtml1dir') || $c->get('installhtmldir') || undef; |
201 | my $libhtml = $c->get('installhtml3dir') || $c->get('installhtmldir') || undef; | |
bb4e9162 YST |
202 | |
203 | $p->{install_sets} = | |
204 | { | |
205 | core => { | |
77e96e88 RGS |
206 | lib => $c->get('installprivlib'), |
207 | arch => $c->get('installarchlib'), | |
208 | bin => $c->get('installbin'), | |
209 | script => $c->get('installscript'), | |
bb4e9162 YST |
210 | bindoc => $bindoc, |
211 | libdoc => $libdoc, | |
212 | binhtml => $binhtml, | |
213 | libhtml => $libhtml, | |
214 | }, | |
215 | site => { | |
77e96e88 RGS |
216 | lib => $c->get('installsitelib'), |
217 | arch => $c->get('installsitearch'), | |
218 | bin => $c->get('installsitebin') || $c->get('installbin'), | |
219 | script => $c->get('installsitescript') || | |
220 | $c->get('installsitebin') || $c->get('installscript'), | |
221 | bindoc => $c->get('installsiteman1dir') || $bindoc, | |
222 | libdoc => $c->get('installsiteman3dir') || $libdoc, | |
223 | binhtml => $c->get('installsitehtml1dir') || $binhtml, | |
224 | libhtml => $c->get('installsitehtml3dir') || $libhtml, | |
bb4e9162 YST |
225 | }, |
226 | vendor => { | |
77e96e88 RGS |
227 | lib => $c->get('installvendorlib'), |
228 | arch => $c->get('installvendorarch'), | |
229 | bin => $c->get('installvendorbin') || $c->get('installbin'), | |
230 | script => $c->get('installvendorscript') || | |
231 | $c->get('installvendorbin') || $c->get('installscript'), | |
232 | bindoc => $c->get('installvendorman1dir') || $bindoc, | |
233 | libdoc => $c->get('installvendorman3dir') || $libdoc, | |
234 | binhtml => $c->get('installvendorhtml1dir') || $binhtml, | |
235 | libhtml => $c->get('installvendorhtml3dir') || $libhtml, | |
bb4e9162 YST |
236 | }, |
237 | }; | |
238 | ||
239 | $p->{original_prefix} = | |
240 | { | |
77e96e88 RGS |
241 | core => $c->get('installprefixexp') || $c->get('installprefix') || |
242 | $c->get('prefixexp') || $c->get('prefix') || '', | |
243 | site => $c->get('siteprefixexp'), | |
244 | vendor => $c->get('usevendorprefix') ? $c->get('vendorprefixexp') : '', | |
bb4e9162 YST |
245 | }; |
246 | $p->{original_prefix}{site} ||= $p->{original_prefix}{core}; | |
247 | ||
248 | # Note: you might be tempted to use $Config{installstyle} here | |
249 | # instead of hard-coding lib/perl5, but that's been considered and | |
250 | # (at least for now) rejected. `perldoc Config` has some wisdom | |
251 | # about it. | |
252 | $p->{install_base_relpaths} = | |
253 | { | |
254 | lib => ['lib', 'perl5'], | |
255 | arch => ['lib', 'perl5', $arch], | |
256 | bin => ['bin'], | |
257 | script => ['bin'], | |
258 | bindoc => ['man', 'man1'], | |
259 | libdoc => ['man', 'man3'], | |
260 | binhtml => ['html'], | |
261 | libhtml => ['html'], | |
262 | }; | |
263 | ||
264 | $p->{prefix_relpaths} = | |
265 | { | |
266 | core => { | |
267 | lib => [@libstyle], | |
268 | arch => [@libstyle, $version, $arch], | |
269 | bin => ['bin'], | |
270 | script => ['bin'], | |
271 | bindoc => ['man', 'man1'], | |
272 | libdoc => ['man', 'man3'], | |
273 | binhtml => ['html'], | |
274 | libhtml => ['html'], | |
275 | }, | |
276 | vendor => { | |
277 | lib => [@libstyle], | |
278 | arch => [@libstyle, $version, $arch], | |
279 | bin => ['bin'], | |
280 | script => ['bin'], | |
281 | bindoc => ['man', 'man1'], | |
282 | libdoc => ['man', 'man3'], | |
283 | binhtml => ['html'], | |
284 | libhtml => ['html'], | |
285 | }, | |
286 | site => { | |
287 | lib => [@libstyle, 'site_perl'], | |
288 | arch => [@libstyle, 'site_perl', $version, $arch], | |
289 | bin => ['bin'], | |
290 | script => ['bin'], | |
291 | bindoc => ['man', 'man1'], | |
292 | libdoc => ['man', 'man3'], | |
293 | binhtml => ['html'], | |
294 | libhtml => ['html'], | |
295 | }, | |
296 | }; | |
297 | ||
298 | } | |
299 | ||
300 | sub _find_nested_builds { | |
301 | my $self = shift; | |
302 | my $r = $self->recurse_into or return; | |
303 | ||
304 | my ($file, @r); | |
305 | if (!ref($r) && $r eq 'auto') { | |
306 | local *DH; | |
307 | opendir DH, $self->base_dir | |
308 | or die "Can't scan directory " . $self->base_dir . " for nested builds: $!"; | |
309 | while (defined($file = readdir DH)) { | |
310 | my $subdir = File::Spec->catdir( $self->base_dir, $file ); | |
311 | next unless -d $subdir; | |
312 | push @r, $subdir if -e File::Spec->catfile( $subdir, 'Build.PL' ); | |
313 | } | |
314 | } | |
315 | ||
316 | $self->recurse_into(\@r); | |
317 | } | |
318 | ||
319 | sub cwd { | |
320 | require Cwd; | |
321 | return Cwd::cwd(); | |
322 | } | |
323 | ||
a314697d RS |
324 | sub _quote_args { |
325 | # Returns a string that can become [part of] a command line with | |
326 | # proper quoting so that the subprocess sees this same list of args. | |
327 | my ($self, @args) = @_; | |
328 | ||
329 | my $return_args = ''; | |
330 | my @quoted; | |
331 | ||
332 | for (@args) { | |
333 | if ( /^[^\s*?!$<>;\\|'"\[\]\{\}]+$/ ) { | |
334 | # Looks pretty safe | |
335 | push @quoted, $_; | |
336 | } else { | |
337 | # XXX this will obviously have to improve - is there already a | |
338 | # core module lying around that does proper quoting? | |
339 | s/"/"'"'"/g; | |
340 | push @quoted, qq("$_"); | |
341 | } | |
342 | } | |
343 | ||
344 | return join " ", @quoted; | |
345 | } | |
346 | ||
347 | sub _backticks { | |
a314697d | 348 | my ($self, @cmd) = @_; |
dc8021d3 | 349 | if ($self->have_forkpipe) { |
a314697d | 350 | local *FH; |
77e96e88 | 351 | my $pid = open *FH, "-|"; |
dc8021d3 SP |
352 | if ($pid) { |
353 | return wantarray ? <FH> : join '', <FH>; | |
354 | } else { | |
355 | die "Can't execute @cmd: $!\n" unless defined $pid; | |
356 | exec { $cmd[0] } @cmd; | |
357 | } | |
a314697d RS |
358 | } else { |
359 | my $cmd = $self->_quote_args(@cmd); | |
360 | return `$cmd`; | |
361 | } | |
362 | } | |
363 | ||
dc8021d3 | 364 | sub have_forkpipe { 1 } |
a314697d RS |
365 | |
366 | # Determine whether a given binary is the same as the perl | |
367 | # (configuration) that started this process. | |
bb4e9162 YST |
368 | sub _perl_is_same { |
369 | my ($self, $perl) = @_; | |
a314697d RS |
370 | |
371 | my @cmd = ($perl); | |
372 | ||
373 | # When run from the perl core, @INC will include the directories | |
374 | # where perl is yet to be installed. We need to reference the | |
375 | # absolute path within the source distribution where it can find | |
376 | # it's Config.pm This also prevents us from picking up a Config.pm | |
377 | # from a different configuration that happens to be already | |
378 | # installed in @INC. | |
379 | if ($ENV{PERL_CORE}) { | |
380 | push @cmd, '-I' . File::Spec->catdir(File::Basename::dirname($perl), 'lib'); | |
381 | } | |
382 | ||
383 | push @cmd, qw(-MConfig=myconfig -e print -e myconfig); | |
384 | return $self->_backticks(@cmd) eq Config->myconfig; | |
bb4e9162 YST |
385 | } |
386 | ||
a314697d RS |
387 | # Returns the absolute path of the perl interperter used to invoke |
388 | # this process. The path is derived from $^X or $Config{perlpath}. On | |
389 | # some platforms $^X contains the complete absolute path of the | |
390 | # interpreter, on other it may contain a relative path, or simply | |
391 | # 'perl'. This can also vary depending on whether a path was supplied | |
392 | # when perl was invoked. Additionally, the value in $^X may omit the | |
393 | # executable extension on platforms that use one. It's a fatal error | |
394 | # if the interpreter can't be found because it can result in undefined | |
395 | # behavior by routines that depend on it (generating errors or | |
396 | # invoking the wrong perl. | |
bb4e9162 | 397 | sub find_perl_interpreter { |
bb4e9162 | 398 | my $proto = shift; |
77e96e88 | 399 | my $c = ref($proto) ? $proto->{config} : 'Module::Build::Config'; |
bb4e9162 | 400 | |
a314697d RS |
401 | my $perl = $^X; |
402 | my $perl_basename = File::Basename::basename($perl); | |
403 | ||
404 | my @potential_perls; | |
405 | ||
406 | # Try 1, Check $^X for absolute path | |
407 | push( @potential_perls, $perl ) | |
408 | if File::Spec->file_name_is_absolute($perl); | |
409 | ||
410 | # Try 2, Check $^X for a valid relative path | |
411 | my $abs_perl = File::Spec->rel2abs($perl); | |
412 | push( @potential_perls, $abs_perl ); | |
47f13fd5 | 413 | |
a314697d RS |
414 | # Try 3, Last ditch effort: These two option use hackery to try to locate |
415 | # a suitable perl. The hack varies depending on whether we are running | |
416 | # from an installed perl or an uninstalled perl in the perl source dist. | |
47f13fd5 | 417 | if ($ENV{PERL_CORE}) { |
a314697d RS |
418 | |
419 | # Try 3.A, If we are in a perl source tree, running an uninstalled | |
420 | # perl, we can keep moving up the directory tree until we find our | |
421 | # binary. We wouldn't do this under any other circumstances. | |
422 | ||
47f13fd5 SP |
423 | # CBuilder is also in the core, so it should be available here |
424 | require ExtUtils::CBuilder; | |
a314697d RS |
425 | my $perl_src = ExtUtils::CBuilder->perl_src; |
426 | if ( defined($perl_src) && length($perl_src) ) { | |
427 | my $uninstperl = | |
428 | File::Spec->rel2abs(File::Spec->catfile( $perl_src, $perl_basename )); | |
429 | push( @potential_perls, $uninstperl ); | |
430 | } | |
431 | ||
432 | } else { | |
433 | ||
434 | # Try 3.B, First look in $Config{perlpath}, then search the users | |
435 | # PATH. We do not want to do either if we are running from an | |
436 | # uninstalled perl in a perl source tree. | |
437 | ||
77e96e88 | 438 | push( @potential_perls, $c->get('perlpath') ); |
a314697d RS |
439 | |
440 | push( @potential_perls, | |
441 | map File::Spec->catfile($_, $perl_basename), File::Spec->path() ); | |
47f13fd5 SP |
442 | } |
443 | ||
a314697d RS |
444 | # Now that we've enumerated the potential perls, it's time to test |
445 | # them to see if any of them match our configuration, returning the | |
446 | # absolute path of the first successful match. | |
77e96e88 | 447 | my $exe = $c->get('exe_ext'); |
a314697d RS |
448 | foreach my $thisperl ( @potential_perls ) { |
449 | ||
d9103e67 | 450 | if (defined $exe and $proto->os_type ne 'VMS') { |
a314697d RS |
451 | $thisperl .= $exe unless $thisperl =~ m/$exe$/i; |
452 | } | |
453 | ||
454 | if ( -f $thisperl && $proto->_perl_is_same($thisperl) ) { | |
455 | return $thisperl; | |
456 | } | |
bb4e9162 | 457 | } |
a314697d RS |
458 | |
459 | # We've tried all alternatives, and didn't find a perl that matches | |
460 | # our configuration. Throw an exception, and list alternatives we tried. | |
461 | my @paths = map File::Basename::dirname($_), @potential_perls; | |
462 | die "Can't locate the perl binary used to run this script " . | |
463 | "in (@paths)\n"; | |
bb4e9162 YST |
464 | } |
465 | ||
466 | sub _is_interactive { | |
467 | return -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ; # Pipe? | |
468 | } | |
469 | ||
7253302f | 470 | # NOTE this is a blocking operation if(-t STDIN) |
dc8021d3 SP |
471 | sub _is_unattended { |
472 | my $self = shift; | |
7253302f SP |
473 | return $ENV{PERL_MM_USE_DEFAULT} || |
474 | ( !$self->_is_interactive && eof STDIN ); | |
dc8021d3 SP |
475 | } |
476 | ||
477 | sub _readline { | |
478 | my $self = shift; | |
479 | return undef if $self->_is_unattended; | |
480 | ||
481 | my $answer = <STDIN>; | |
482 | chomp $answer if defined $answer; | |
483 | return $answer; | |
484 | } | |
485 | ||
bb4e9162 YST |
486 | sub prompt { |
487 | my $self = shift; | |
dc8021d3 SP |
488 | my $mess = shift |
489 | or die "prompt() called without a prompt message"; | |
490 | ||
7253302f SP |
491 | # use a list to distinguish a default of undef() from no default |
492 | my @def; | |
493 | @def = (shift) if @_; | |
494 | # use dispdef for output | |
495 | my @dispdef = scalar(@def) ? | |
496 | ('[', (defined($def[0]) ? $def[0] . ' ' : ''), ']') : | |
497 | (' ', ''); | |
498 | ||
499 | local $|=1; | |
500 | print "$mess ", @dispdef; | |
501 | ||
502 | if ( $self->_is_unattended && !@def ) { | |
dc8021d3 SP |
503 | die <<EOF; |
504 | ERROR: This build seems to be unattended, but there is no default value | |
505 | for this question. Aborting. | |
506 | EOF | |
507 | } | |
dc8021d3 SP |
508 | |
509 | my $ans = $self->_readline(); | |
510 | ||
b3dfda33 SP |
511 | if ( !defined($ans) # Ctrl-D or unattended |
512 | or !length($ans) ) { # User hit return | |
7253302f SP |
513 | print "$dispdef[1]\n"; |
514 | $ans = scalar(@def) ? $def[0] : ''; | |
bb4e9162 | 515 | } |
dc8021d3 | 516 | |
bb4e9162 YST |
517 | return $ans; |
518 | } | |
519 | ||
520 | sub y_n { | |
521 | my $self = shift; | |
dc8021d3 SP |
522 | my ($mess, $def) = @_; |
523 | ||
524 | die "y_n() called without a prompt message" unless $mess; | |
525 | die "Invalid default value: y_n() default must be 'y' or 'n'" | |
526 | if $def && $def !~ /^[yn]/i; | |
527 | ||
bb4e9162 | 528 | my $answer; |
dc8021d3 | 529 | while (1) { # XXX Infinite or a large number followed by an exception ? |
bb4e9162 YST |
530 | $answer = $self->prompt(@_); |
531 | return 1 if $answer =~ /^y/i; | |
532 | return 0 if $answer =~ /^n/i; | |
dc8021d3 | 533 | local $|=1; |
bb4e9162 YST |
534 | print "Please answer 'y' or 'n'.\n"; |
535 | } | |
536 | } | |
537 | ||
538 | sub current_action { shift->{action} } | |
539 | sub invoked_action { shift->{invoked_action} } | |
540 | ||
541 | sub notes { shift()->{phash}{notes}->access(@_) } | |
542 | sub config_data { shift()->{phash}{config_data}->access(@_) } | |
543 | sub runtime_params { shift->{phash}{runtime_params}->read( @_ ? shift : () ) } # Read-only | |
544 | sub auto_features { shift()->{phash}{auto_features}->access(@_) } | |
545 | ||
546 | sub features { | |
547 | my $self = shift; | |
548 | my $ph = $self->{phash}; | |
549 | ||
550 | if (@_) { | |
551 | my $key = shift; | |
552 | if ($ph->{features}->exists($key)) { | |
553 | return $ph->{features}->access($key, @_); | |
554 | } | |
555 | ||
556 | if (my $info = $ph->{auto_features}->access($key)) { | |
557 | my $failures = $self->prereq_failures($info); | |
558 | my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/, | |
559 | keys %$failures ) ? 1 : 0; | |
560 | return !$disabled; | |
561 | } | |
562 | ||
563 | return $ph->{features}->access($key, @_); | |
564 | } | |
565 | ||
566 | # No args - get the auto_features & overlay the regular features | |
567 | my %features; | |
568 | my %auto_features = $ph->{auto_features}->access(); | |
569 | while (my ($name, $info) = each %auto_features) { | |
570 | my $failures = $self->prereq_failures($info); | |
571 | my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/, | |
572 | keys %$failures ) ? 1 : 0; | |
573 | $features{$name} = $disabled ? 0 : 1; | |
574 | } | |
575 | %features = (%features, $ph->{features}->access()); | |
576 | ||
577 | return wantarray ? %features : \%features; | |
578 | } | |
579 | BEGIN { *feature = \&features } | |
580 | ||
581 | sub _mb_feature { | |
582 | my $self = shift; | |
583 | ||
584 | if (($self->module_name || '') eq 'Module::Build') { | |
585 | # We're building Module::Build itself, so ...::ConfigData isn't | |
586 | # valid, but $self->features() should be. | |
587 | return $self->feature(@_); | |
588 | } else { | |
589 | require Module::Build::ConfigData; | |
590 | return Module::Build::ConfigData->feature(@_); | |
591 | } | |
592 | } | |
593 | ||
594 | ||
595 | sub add_build_element { | |
596 | my ($self, $elem) = @_; | |
597 | my $elems = $self->build_elements; | |
598 | push @$elems, $elem unless grep { $_ eq $elem } @$elems; | |
599 | } | |
600 | ||
601 | sub ACTION_config_data { | |
602 | my $self = shift; | |
603 | return unless $self->has_config_data; | |
604 | ||
605 | my $module_name = $self->module_name | |
606 | or die "The config_data feature requires that 'module_name' be set"; | |
607 | my $notes_name = $module_name . '::ConfigData'; # TODO: Customize name ??? | |
608 | my $notes_pm = File::Spec->catfile($self->blib, 'lib', split /::/, "$notes_name.pm"); | |
609 | ||
610 | return if $self->up_to_date(['Build.PL', | |
611 | $self->config_file('config_data'), | |
612 | $self->config_file('features') | |
613 | ], $notes_pm); | |
614 | ||
615 | $self->log_info("Writing config notes to $notes_pm\n"); | |
616 | File::Path::mkpath(File::Basename::dirname($notes_pm)); | |
617 | ||
618 | Module::Build::Notes->write_config_data | |
619 | ( | |
620 | file => $notes_pm, | |
621 | module => $module_name, | |
622 | config_module => $notes_name, | |
623 | config_data => scalar $self->config_data, | |
624 | feature => scalar $self->{phash}{features}->access(), | |
625 | auto_features => scalar $self->auto_features, | |
626 | ); | |
627 | } | |
628 | ||
629 | { | |
630 | my %valid_properties = ( __PACKAGE__, {} ); | |
631 | my %additive_properties; | |
632 | ||
633 | sub _mb_classes { | |
634 | my $class = ref($_[0]) || $_[0]; | |
635 | return ($class, $class->mb_parents); | |
636 | } | |
637 | ||
638 | sub valid_property { | |
639 | my ($class, $prop) = @_; | |
640 | return grep exists( $valid_properties{$_}{$prop} ), $class->_mb_classes; | |
641 | } | |
642 | ||
643 | sub valid_properties { | |
644 | return keys %{ shift->valid_properties_defaults() }; | |
645 | } | |
646 | ||
647 | sub valid_properties_defaults { | |
648 | my %out; | |
649 | for (reverse shift->_mb_classes) { | |
650 | @out{ keys %{ $valid_properties{$_} } } = values %{ $valid_properties{$_} }; | |
651 | } | |
652 | return \%out; | |
653 | } | |
654 | ||
655 | sub array_properties { | |
656 | for (shift->_mb_classes) { | |
657 | return @{$additive_properties{$_}->{ARRAY}} | |
658 | if exists $additive_properties{$_}->{ARRAY}; | |
659 | } | |
660 | } | |
661 | ||
662 | sub hash_properties { | |
663 | for (shift->_mb_classes) { | |
664 | return @{$additive_properties{$_}->{'HASH'}} | |
665 | if exists $additive_properties{$_}->{'HASH'}; | |
666 | } | |
667 | } | |
668 | ||
669 | sub add_property { | |
670 | my ($class, $property, $default) = @_; | |
671 | die "Property '$property' already exists" if $class->valid_property($property); | |
672 | ||
673 | $valid_properties{$class}{$property} = $default; | |
674 | ||
675 | my $type = ref $default; | |
676 | if ($type) { | |
677 | push @{$additive_properties{$class}->{$type}}, $property; | |
678 | } | |
679 | ||
680 | unless ($class->can($property)) { | |
681 | no strict 'refs'; | |
682 | if ( $type eq 'HASH' ) { | |
683 | *{"$class\::$property"} = sub { | |
684 | my $self = shift; | |
77e96e88 | 685 | my $x = $self->{properties}; |
bb4e9162 YST |
686 | return $x->{$property} unless @_; |
687 | ||
688 | if ( defined($_[0]) && !ref($_[0]) ) { | |
689 | if ( @_ == 1 ) { | |
690 | return exists( $x->{$property}{$_[0]} ) ? | |
691 | $x->{$property}{$_[0]} : undef; | |
692 | } elsif ( @_ % 2 == 0 ) { | |
693 | my %args = @_; | |
694 | while ( my($k, $v) = each %args ) { | |
695 | $x->{$property}{$k} = $v; | |
696 | } | |
697 | } else { | |
698 | die "Unexpected arguments for property '$property'\n"; | |
699 | } | |
700 | } else { | |
701 | $x->{$property} = $_[0]; | |
702 | } | |
703 | }; | |
704 | ||
705 | } else { | |
706 | *{"$class\::$property"} = sub { | |
707 | my $self = shift; | |
708 | $self->{properties}{$property} = shift if @_; | |
709 | return $self->{properties}{$property}; | |
710 | } | |
711 | } | |
712 | ||
713 | } | |
714 | return $class; | |
715 | } | |
716 | ||
717 | sub _set_defaults { | |
718 | my $self = shift; | |
719 | ||
720 | # Set the build class. | |
721 | $self->{properties}{build_class} ||= ref $self; | |
722 | ||
723 | # If there was no orig_dir, set to the same as base_dir | |
724 | $self->{properties}{orig_dir} ||= $self->{properties}{base_dir}; | |
725 | ||
726 | my $defaults = $self->valid_properties_defaults; | |
727 | ||
728 | foreach my $prop (keys %$defaults) { | |
729 | $self->{properties}{$prop} = $defaults->{$prop} | |
730 | unless exists $self->{properties}{$prop}; | |
731 | } | |
732 | ||
733 | # Copy defaults for arrays any arrays. | |
734 | for my $prop ($self->array_properties) { | |
735 | $self->{properties}{$prop} = [@{$defaults->{$prop}}] | |
736 | unless exists $self->{properties}{$prop}; | |
737 | } | |
738 | # Copy defaults for arrays any hashes. | |
739 | for my $prop ($self->hash_properties) { | |
740 | $self->{properties}{$prop} = {%{$defaults->{$prop}}} | |
741 | unless exists $self->{properties}{$prop}; | |
742 | } | |
743 | } | |
744 | ||
745 | } | |
746 | ||
747 | # Add the default properties. | |
748 | __PACKAGE__->add_property(blib => 'blib'); | |
749 | __PACKAGE__->add_property(build_class => 'Module::Build'); | |
750 | __PACKAGE__->add_property(build_elements => [qw(PL support pm xs pod script)]); | |
751 | __PACKAGE__->add_property(build_script => 'Build'); | |
752 | __PACKAGE__->add_property(build_bat => 0); | |
753 | __PACKAGE__->add_property(config_dir => '_build'); | |
754 | __PACKAGE__->add_property(include_dirs => []); | |
755 | __PACKAGE__->add_property(installdirs => 'site'); | |
756 | __PACKAGE__->add_property(metafile => 'META.yml'); | |
757 | __PACKAGE__->add_property(recurse_into => []); | |
758 | __PACKAGE__->add_property(use_rcfile => 1); | |
a314697d | 759 | __PACKAGE__->add_property(create_packlist => 1); |
0ec9ad96 | 760 | __PACKAGE__->add_property(allow_mb_mismatch => 0); |
77e96e88 | 761 | __PACKAGE__->add_property(config => undef); |
bb4e9162 YST |
762 | |
763 | { | |
764 | my $Is_ActivePerl = eval {require ActivePerl::DocTools}; | |
765 | __PACKAGE__->add_property(html_css => $Is_ActivePerl ? 'Active.css' : ''); | |
766 | } | |
767 | ||
768 | { | |
769 | my @prereq_action_types = qw(requires build_requires conflicts recommends); | |
770 | foreach my $type (@prereq_action_types) { | |
771 | __PACKAGE__->add_property($type => {}); | |
772 | } | |
773 | __PACKAGE__->add_property(prereq_action_types => \@prereq_action_types); | |
774 | } | |
775 | ||
776 | __PACKAGE__->add_property($_ => {}) for qw( | |
bb4e9162 YST |
777 | get_options |
778 | install_base_relpaths | |
779 | install_path | |
780 | install_sets | |
781 | meta_add | |
782 | meta_merge | |
783 | original_prefix | |
784 | prefix_relpaths | |
785 | ); | |
786 | ||
787 | __PACKAGE__->add_property($_) for qw( | |
788 | PL_files | |
789 | autosplit | |
790 | base_dir | |
791 | bindoc_dirs | |
792 | c_source | |
793 | create_makefile_pl | |
794 | create_readme | |
795 | debugger | |
796 | destdir | |
797 | dist_abstract | |
798 | dist_author | |
799 | dist_name | |
800 | dist_version | |
801 | dist_version_from | |
802 | extra_compiler_flags | |
803 | extra_linker_flags | |
804 | has_config_data | |
805 | install_base | |
806 | libdoc_dirs | |
807 | license | |
808 | magic_number | |
809 | mb_version | |
810 | module_name | |
811 | orig_dir | |
812 | perl | |
813 | pm_files | |
814 | pod_files | |
815 | pollute | |
816 | prefix | |
817 | quiet | |
818 | recursive_test_files | |
819 | script_files | |
820 | scripts | |
821 | test_files | |
822 | verbose | |
823 | xs_files | |
824 | ); | |
825 | ||
77e96e88 RGS |
826 | sub config { |
827 | my $self = shift; | |
828 | my $c = ref($self) ? $self->{config} : 'Module::Build::Config'; | |
829 | return $c->all_config unless @_; | |
830 | ||
831 | my $key = shift; | |
832 | return $c->get($key) unless @_; | |
833 | ||
834 | my $val = shift; | |
835 | return $c->set($key => $val); | |
836 | } | |
bb4e9162 YST |
837 | |
838 | sub mb_parents { | |
839 | # Code borrowed from Class::ISA. | |
840 | my @in_stack = (shift); | |
841 | my %seen = ($in_stack[0] => 1); | |
842 | ||
843 | my ($current, @out); | |
844 | while (@in_stack) { | |
845 | next unless defined($current = shift @in_stack) | |
846 | && $current->isa('Module::Build::Base'); | |
847 | push @out, $current; | |
848 | next if $current eq 'Module::Build::Base'; | |
849 | no strict 'refs'; | |
850 | unshift @in_stack, | |
851 | map { | |
852 | my $c = $_; # copy, to avoid being destructive | |
853 | substr($c,0,2) = "main::" if substr($c,0,2) eq '::'; | |
854 | # Canonize the :: -> main::, ::foo -> main::foo thing. | |
855 | # Should I ever canonize the Foo'Bar = Foo::Bar thing? | |
856 | $seen{$c}++ ? () : $c; | |
857 | } @{"$current\::ISA"}; | |
858 | ||
859 | # I.e., if this class has any parents (at least, ones I've never seen | |
860 | # before), push them, in order, onto the stack of classes I need to | |
861 | # explore. | |
862 | } | |
863 | shift @out; | |
864 | return @out; | |
865 | } | |
866 | ||
867 | sub extra_linker_flags { shift->_list_accessor('extra_linker_flags', @_) } | |
868 | sub extra_compiler_flags { shift->_list_accessor('extra_compiler_flags', @_) } | |
869 | ||
870 | sub _list_accessor { | |
871 | (my $self, local $_) = (shift, shift); | |
872 | my $p = $self->{properties}; | |
873 | $p->{$_} = [@_] if @_; | |
874 | $p->{$_} = [] unless exists $p->{$_}; | |
875 | return ref($p->{$_}) ? $p->{$_} : [$p->{$_}]; | |
876 | } | |
877 | ||
878 | # XXX Problem - if Module::Build is loaded from a different directory, | |
879 | # it'll look for (and perhaps destroy/create) a _build directory. | |
880 | sub subclass { | |
881 | my ($pack, %opts) = @_; | |
882 | ||
883 | my $build_dir = '_build'; # XXX The _build directory is ostensibly settable by the user. Shouldn't hard-code here. | |
884 | $pack->delete_filetree($build_dir) if -e $build_dir; | |
885 | ||
886 | die "Must provide 'code' or 'class' option to subclass()\n" | |
887 | unless $opts{code} or $opts{class}; | |
888 | ||
889 | $opts{code} ||= ''; | |
890 | $opts{class} ||= 'MyModuleBuilder'; | |
891 | ||
892 | my $filename = File::Spec->catfile($build_dir, 'lib', split '::', $opts{class}) . '.pm'; | |
893 | my $filedir = File::Basename::dirname($filename); | |
894 | $pack->log_info("Creating custom builder $filename in $filedir\n"); | |
895 | ||
896 | File::Path::mkpath($filedir); | |
897 | die "Can't create directory $filedir: $!" unless -d $filedir; | |
898 | ||
899 | my $fh = IO::File->new("> $filename") or die "Can't create $filename: $!"; | |
900 | print $fh <<EOF; | |
901 | package $opts{class}; | |
902 | use $pack; | |
903 | \@ISA = qw($pack); | |
904 | $opts{code} | |
905 | 1; | |
906 | EOF | |
907 | close $fh; | |
908 | ||
909 | unshift @INC, File::Spec->catdir(File::Spec->rel2abs($build_dir), 'lib'); | |
910 | eval "use $opts{class}"; | |
911 | die $@ if $@; | |
912 | ||
913 | return $opts{class}; | |
914 | } | |
915 | ||
916 | sub dist_name { | |
917 | my $self = shift; | |
918 | my $p = $self->{properties}; | |
919 | return $p->{dist_name} if defined $p->{dist_name}; | |
920 | ||
921 | die "Can't determine distribution name, must supply either 'dist_name' or 'module_name' parameter" | |
47f13fd5 | 922 | unless $self->module_name; |
bb4e9162 | 923 | |
47f13fd5 | 924 | ($p->{dist_name} = $self->module_name) =~ s/::/-/g; |
bb4e9162 YST |
925 | |
926 | return $p->{dist_name}; | |
927 | } | |
928 | ||
47f13fd5 | 929 | sub dist_version_from { |
bb4e9162 YST |
930 | my ($self) = @_; |
931 | my $p = $self->{properties}; | |
932 | if ($self->module_name) { | |
47f13fd5 | 933 | $p->{dist_version_from} ||= |
bb4e9162 | 934 | join( '/', 'lib', split(/::/, $self->module_name) ) . '.pm'; |
bb4e9162 | 935 | } |
47f13fd5 | 936 | return $p->{dist_version_from} || undef; |
bb4e9162 YST |
937 | } |
938 | ||
939 | sub dist_version { | |
940 | my ($self) = @_; | |
941 | my $p = $self->{properties}; | |
942 | ||
943 | return $p->{dist_version} if defined $p->{dist_version}; | |
bb4e9162 | 944 | |
47f13fd5 SP |
945 | if ( my $dist_version_from = $self->dist_version_from ) { |
946 | my $version_from = File::Spec->catfile( split( qr{/}, $dist_version_from ) ); | |
bb4e9162 YST |
947 | my $pm_info = Module::Build::ModuleInfo->new_from_file( $version_from ) |
948 | or die "Can't find file $version_from to determine version"; | |
949 | $p->{dist_version} = $pm_info->version(); | |
950 | } | |
951 | ||
952 | die ("Can't determine distribution version, must supply either 'dist_version',\n". | |
953 | "'dist_version_from', or 'module_name' parameter") | |
954 | unless $p->{dist_version}; | |
955 | ||
956 | return $p->{dist_version}; | |
957 | } | |
958 | ||
959 | sub dist_author { shift->_pod_parse('author') } | |
960 | sub dist_abstract { shift->_pod_parse('abstract') } | |
961 | ||
962 | sub _pod_parse { | |
963 | my ($self, $part) = @_; | |
964 | my $p = $self->{properties}; | |
965 | my $member = "dist_$part"; | |
966 | return $p->{$member} if defined $p->{$member}; | |
967 | ||
968 | my $docfile = $self->_main_docfile | |
969 | or return; | |
970 | my $fh = IO::File->new($docfile) | |
971 | or return; | |
972 | ||
973 | require Module::Build::PodParser; | |
974 | my $parser = Module::Build::PodParser->new(fh => $fh); | |
975 | my $method = "get_$part"; | |
976 | return $p->{$member} = $parser->$method(); | |
977 | } | |
978 | ||
979 | sub version_from_file { # Method provided for backwards compatability | |
980 | return Module::Build::ModuleInfo->new_from_file($_[1])->version(); | |
981 | } | |
982 | ||
983 | sub find_module_by_name { # Method provided for backwards compatability | |
984 | return Module::Build::ModuleInfo->find_module_by_name(@_[1,2]); | |
985 | } | |
986 | ||
987 | sub add_to_cleanup { | |
988 | my $self = shift; | |
989 | my %files = map {$self->localize_file_path($_), 1} @_; | |
990 | $self->{phash}{cleanup}->write(\%files); | |
991 | } | |
992 | ||
993 | sub cleanup { | |
994 | my $self = shift; | |
995 | my $all = $self->{phash}{cleanup}->read; | |
996 | return keys %$all; | |
997 | } | |
998 | ||
999 | sub config_file { | |
1000 | my $self = shift; | |
1001 | return unless -d $self->config_dir; | |
1002 | return File::Spec->catfile($self->config_dir, @_); | |
1003 | } | |
1004 | ||
1005 | sub read_config { | |
1006 | my ($self) = @_; | |
1007 | ||
1008 | my $file = $self->config_file('build_params') | |
7253302f | 1009 | or die "Can't find 'build_params' in " . $self->config_dir; |
bb4e9162 YST |
1010 | my $fh = IO::File->new($file) or die "Can't read '$file': $!"; |
1011 | my $ref = eval do {local $/; <$fh>}; | |
1012 | die if $@; | |
77e96e88 RGS |
1013 | my $c; |
1014 | ($self->{args}, $c, $self->{properties}) = @$ref; | |
1015 | $self->{config} = Module::Build::Config->new(values => $c); | |
bb4e9162 YST |
1016 | close $fh; |
1017 | } | |
1018 | ||
1019 | sub has_config_data { | |
1020 | my $self = shift; | |
1021 | return scalar grep $self->{phash}{$_}->has_data(), qw(config_data features auto_features); | |
1022 | } | |
1023 | ||
1024 | sub _write_data { | |
1025 | my ($self, $filename, $data) = @_; | |
1026 | ||
1027 | my $file = $self->config_file($filename); | |
1028 | my $fh = IO::File->new("> $file") or die "Can't create '$file': $!"; | |
1029 | local $Data::Dumper::Terse = 1; | |
1030 | print $fh ref($data) ? Data::Dumper::Dumper($data) : $data; | |
1031 | } | |
1032 | ||
1033 | sub write_config { | |
1034 | my ($self) = @_; | |
1035 | ||
1036 | File::Path::mkpath($self->{properties}{config_dir}); | |
1037 | -d $self->{properties}{config_dir} or die "Can't mkdir $self->{properties}{config_dir}: $!"; | |
1038 | ||
1039 | my @items = @{ $self->prereq_action_types }; | |
1040 | $self->_write_data('prereqs', { map { $_, $self->$_() } @items }); | |
77e96e88 | 1041 | $self->_write_data('build_params', [$self->{args}, $self->{config}->values_set, $self->{properties}]); |
bb4e9162 YST |
1042 | |
1043 | # Set a new magic number and write it to a file | |
1044 | $self->_write_data('magicnum', $self->magic_number(int rand 1_000_000)); | |
1045 | ||
1046 | $self->{phash}{$_}->write() foreach qw(notes cleanup features auto_features config_data runtime_params); | |
1047 | } | |
1048 | ||
1049 | sub check_autofeatures { | |
1050 | my ($self) = @_; | |
1051 | my $features = $self->auto_features; | |
1052 | ||
1053 | return unless %$features; | |
1054 | ||
1055 | $self->log_info("Checking features:\n"); | |
1056 | ||
1057 | my $max_name_len; | |
1058 | $max_name_len = ( length($_) > $max_name_len ) ? | |
1059 | length($_) : $max_name_len | |
1060 | for keys %$features; | |
1061 | ||
1062 | while (my ($name, $info) = each %$features) { | |
1063 | $self->log_info(" $name" . '.' x ($max_name_len - length($name) + 4)); | |
1064 | ||
1065 | if ( my $failures = $self->prereq_failures($info) ) { | |
1066 | my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/, | |
1067 | keys %$failures ) ? 1 : 0; | |
1068 | $self->log_info( $disabled ? "disabled\n" : "enabled\n" ); | |
1069 | ||
1070 | my $log_text; | |
1071 | while (my ($type, $prereqs) = each %$failures) { | |
1072 | while (my ($module, $status) = each %$prereqs) { | |
1073 | my $required = | |
1074 | ($type =~ /^(?:\w+_)?(?:requires|conflicts)$/) ? 1 : 0; | |
1075 | my $prefix = ($required) ? '-' : '*'; | |
1076 | $log_text .= " $prefix $status->{message}\n"; | |
1077 | } | |
1078 | } | |
1079 | $self->log_warn("$log_text") unless $self->quiet; | |
1080 | } else { | |
1081 | $self->log_info("enabled\n"); | |
1082 | } | |
1083 | } | |
1084 | ||
1085 | $self->log_warn("\n"); | |
1086 | } | |
1087 | ||
1088 | sub prereq_failures { | |
1089 | my ($self, $info) = @_; | |
1090 | ||
1091 | my @types = @{ $self->prereq_action_types }; | |
1092 | $info ||= {map {$_, $self->$_()} @types}; | |
1093 | ||
1094 | my $out; | |
1095 | ||
1096 | foreach my $type (@types) { | |
1097 | my $prereqs = $info->{$type}; | |
1098 | while ( my ($modname, $spec) = each %$prereqs ) { | |
1099 | my $status = $self->check_installed_status($modname, $spec); | |
1100 | ||
1101 | if ($type =~ /^(?:\w+_)?conflicts$/) { | |
1102 | next if !$status->{ok}; | |
1103 | $status->{conflicts} = delete $status->{need}; | |
1104 | $status->{message} = "$modname ($status->{have}) conflicts with this distribution"; | |
1105 | ||
1106 | } elsif ($type =~ /^(?:\w+_)?recommends$/) { | |
1107 | next if $status->{ok}; | |
0ec9ad96 | 1108 | $status->{message} = (!ref($status->{have}) && $status->{have} eq '<none>' |
bb4e9162 YST |
1109 | ? "Optional prerequisite $modname is not installed" |
1110 | : "$modname ($status->{have}) is installed, but we prefer to have $spec"); | |
1111 | } else { | |
1112 | next if $status->{ok}; | |
1113 | } | |
1114 | ||
1115 | $out->{$type}{$modname} = $status; | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | return $out; | |
1120 | } | |
1121 | ||
1122 | # returns a hash of defined prerequisites; i.e. only prereq types with values | |
1123 | sub _enum_prereqs { | |
1124 | my $self = shift; | |
1125 | my %prereqs; | |
1126 | foreach my $type ( @{ $self->prereq_action_types } ) { | |
1127 | if ( $self->can( $type ) ) { | |
1128 | my $prereq = $self->$type() || {}; | |
1129 | $prereqs{$type} = $prereq if %$prereq; | |
1130 | } | |
1131 | } | |
1132 | return \%prereqs; | |
1133 | } | |
1134 | ||
1135 | sub check_prereq { | |
1136 | my $self = shift; | |
1137 | ||
1138 | # If we have XS files, make sure we can process them. | |
1139 | my $xs_files = $self->find_xs_files; | |
1140 | if (keys %$xs_files && !$self->_mb_feature('C_support')) { | |
1141 | $self->log_warn("Warning: this distribution contains XS files, ". | |
77e96e88 RGS |
1142 | "but Module::Build is not configured with C_support. ". |
1143 | "Please install ExtUtils::CBuilder to enable C_support.\n"); | |
bb4e9162 YST |
1144 | } |
1145 | ||
1146 | # Check to see if there are any prereqs to check | |
1147 | my $info = $self->_enum_prereqs; | |
1148 | return 1 unless $info; | |
1149 | ||
1150 | $self->log_info("Checking prerequisites...\n"); | |
1151 | ||
1152 | my $failures = $self->prereq_failures($info); | |
1153 | ||
1154 | if ( $failures ) { | |
1155 | ||
1156 | while (my ($type, $prereqs) = each %$failures) { | |
1157 | while (my ($module, $status) = each %$prereqs) { | |
1158 | my $prefix = ($type =~ /^(?:\w+_)?recommends$/) ? '*' : '- ERROR:'; | |
1159 | $self->log_warn(" $prefix $status->{message}\n"); | |
1160 | } | |
1161 | } | |
1162 | ||
1163 | $self->log_warn(<<EOF); | |
1164 | ||
1165 | ERRORS/WARNINGS FOUND IN PREREQUISITES. You may wish to install the versions | |
1166 | of the modules indicated above before proceeding with this installation | |
1167 | ||
1168 | EOF | |
1169 | return 0; | |
1170 | ||
1171 | } else { | |
1172 | ||
1173 | $self->log_info("Looks good\n\n"); | |
1174 | return 1; | |
1175 | ||
1176 | } | |
1177 | } | |
1178 | ||
1179 | sub perl_version { | |
1180 | my ($self) = @_; | |
1181 | # Check the current perl interpreter | |
1182 | # It's much more convenient to use $] here than $^V, but 'man | |
1183 | # perlvar' says I'm not supposed to. Bloody tyrant. | |
1184 | return $^V ? $self->perl_version_to_float(sprintf "%vd", $^V) : $]; | |
1185 | } | |
1186 | ||
1187 | sub perl_version_to_float { | |
1188 | my ($self, $version) = @_; | |
1189 | $version =~ s/\./../; | |
1190 | $version =~ s/\.(\d+)/sprintf '%03d', $1/eg; | |
1191 | return $version; | |
1192 | } | |
1193 | ||
1194 | sub _parse_conditions { | |
1195 | my ($self, $spec) = @_; | |
1196 | ||
1197 | if ($spec =~ /^\s*([\w.]+)\s*$/) { # A plain number, maybe with dots, letters, and underscores | |
1198 | return (">= $spec"); | |
1199 | } else { | |
1200 | return split /\s*,\s*/, $spec; | |
1201 | } | |
1202 | } | |
1203 | ||
1204 | sub check_installed_status { | |
1205 | my ($self, $modname, $spec) = @_; | |
1206 | my %status = (need => $spec); | |
1207 | ||
1208 | if ($modname eq 'perl') { | |
1209 | $status{have} = $self->perl_version; | |
1210 | ||
1211 | } elsif (eval { no strict; $status{have} = ${"${modname}::VERSION"} }) { | |
1212 | # Don't try to load if it's already loaded | |
1213 | ||
1214 | } else { | |
1215 | my $pm_info = Module::Build::ModuleInfo->new_from_module( $modname ); | |
1216 | unless (defined( $pm_info )) { | |
1217 | @status{ qw(have message) } = ('<none>', "$modname is not installed"); | |
1218 | return \%status; | |
1219 | } | |
1220 | ||
1221 | $status{have} = $pm_info->version(); | |
1222 | if ($spec and !$status{have}) { | |
1223 | @status{ qw(have message) } = (undef, "Couldn't find a \$VERSION in prerequisite $modname"); | |
1224 | return \%status; | |
1225 | } | |
1226 | } | |
1227 | ||
1228 | my @conditions = $self->_parse_conditions($spec); | |
1229 | ||
1230 | foreach (@conditions) { | |
1231 | my ($op, $version) = /^\s* (<=?|>=?|==|!=) \s* ([\w.]+) \s*$/x | |
1232 | or die "Invalid prerequisite condition '$_' for $modname"; | |
1233 | ||
1234 | $version = $self->perl_version_to_float($version) | |
1235 | if $modname eq 'perl'; | |
1236 | ||
1237 | next if $op eq '>=' and !$version; # Module doesn't have to actually define a $VERSION | |
1238 | ||
1239 | unless ($self->compare_versions( $status{have}, $op, $version )) { | |
1240 | $status{message} = "$modname ($status{have}) is installed, but we need version $op $version"; | |
1241 | return \%status; | |
1242 | } | |
1243 | } | |
1244 | ||
1245 | $status{ok} = 1; | |
1246 | return \%status; | |
1247 | } | |
1248 | ||
1249 | sub compare_versions { | |
1250 | my $self = shift; | |
1251 | my ($v1, $op, $v2) = @_; | |
b3dfda33 SP |
1252 | $v1 = Module::Build::Version->new($v1) |
1253 | unless UNIVERSAL::isa($v1,'Module::Build::Version'); | |
bb4e9162 YST |
1254 | |
1255 | my $eval_str = "\$v1 $op \$v2"; | |
1256 | my $result = eval $eval_str; | |
1257 | $self->log_warn("error comparing versions: '$eval_str' $@") if $@; | |
1258 | ||
1259 | return $result; | |
1260 | } | |
1261 | ||
1262 | # I wish I could set $! to a string, but I can't, so I use $@ | |
1263 | sub check_installed_version { | |
1264 | my ($self, $modname, $spec) = @_; | |
1265 | ||
1266 | my $status = $self->check_installed_status($modname, $spec); | |
1267 | ||
1268 | if ($status->{ok}) { | |
1269 | return $status->{have} if $status->{have} and $status->{have} ne '<none>'; | |
1270 | return '0 but true'; | |
1271 | } | |
1272 | ||
1273 | $@ = $status->{message}; | |
1274 | return 0; | |
1275 | } | |
1276 | ||
1277 | sub make_executable { | |
1278 | # Perl's chmod() is mapped to useful things on various non-Unix | |
1279 | # platforms, so we use it in the base class even though it looks | |
1280 | # Unixish. | |
1281 | ||
1282 | my $self = shift; | |
1283 | foreach (@_) { | |
1284 | my $current_mode = (stat $_)[2]; | |
77e96e88 | 1285 | chmod $current_mode | oct(111), $_; |
bb4e9162 YST |
1286 | } |
1287 | } | |
1288 | ||
f943a5bf SP |
1289 | sub is_executable { |
1290 | # We assume this does the right thing on generic platforms, though | |
1291 | # we do some other more specific stuff on Unixish platforms. | |
1292 | my ($self, $file) = @_; | |
1293 | return -x $file; | |
1294 | } | |
1295 | ||
bb4e9162 YST |
1296 | sub _startperl { shift()->config('startperl') } |
1297 | ||
1298 | # Return any directories in @INC which are not in the default @INC for | |
1299 | # this perl. For example, stuff passed in with -I or loaded with "use lib". | |
1300 | sub _added_to_INC { | |
1301 | my $self = shift; | |
1302 | ||
1303 | my %seen; | |
1304 | $seen{$_}++ foreach $self->_default_INC; | |
1305 | return grep !$seen{$_}++, @INC; | |
1306 | } | |
1307 | ||
1308 | # Determine the default @INC for this Perl | |
1309 | { | |
1310 | my @default_inc; # Memoize | |
1311 | sub _default_INC { | |
1312 | my $self = shift; | |
1313 | return @default_inc if @default_inc; | |
1314 | ||
1315 | local $ENV{PERL5LIB}; # this is not considered part of the default. | |
1316 | ||
1317 | my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter; | |
1318 | ||
a314697d | 1319 | my @inc = $self->_backticks($perl, '-le', 'print for @INC'); |
bb4e9162 YST |
1320 | chomp @inc; |
1321 | ||
1322 | return @default_inc = @inc; | |
1323 | } | |
1324 | } | |
1325 | ||
1326 | sub print_build_script { | |
1327 | my ($self, $fh) = @_; | |
1328 | ||
1329 | my $build_package = $self->build_class; | |
1330 | ||
1331 | my $closedata=""; | |
1332 | ||
1333 | my %q = map {$_, $self->$_()} qw(config_dir base_dir); | |
1334 | ||
1335 | my $case_tolerant = 0+(File::Spec->can('case_tolerant') | |
1336 | && File::Spec->case_tolerant); | |
1337 | $q{base_dir} = uc $q{base_dir} if $case_tolerant; | |
1338 | $q{base_dir} = Win32::GetShortPathName($q{base_dir}) if $^O eq 'MSWin32'; | |
1339 | ||
1340 | $q{magic_numfile} = $self->config_file('magicnum'); | |
1341 | ||
1342 | my @myINC = $self->_added_to_INC; | |
1343 | for (@myINC, values %q) { | |
1344 | $_ = File::Spec->canonpath( $_ ); | |
1345 | s/([\\\'])/\\$1/g; | |
1346 | } | |
1347 | ||
1348 | my $quoted_INC = join ",\n", map " '$_'", @myINC; | |
1349 | my $shebang = $self->_startperl; | |
1350 | my $magic_number = $self->magic_number; | |
1351 | ||
1352 | print $fh <<EOF; | |
1353 | $shebang | |
1354 | ||
1355 | use strict; | |
1356 | use Cwd; | |
1357 | use File::Basename; | |
1358 | use File::Spec; | |
1359 | ||
1360 | sub magic_number_matches { | |
1361 | return 0 unless -e '$q{magic_numfile}'; | |
1362 | local *FH; | |
1363 | open FH, '$q{magic_numfile}' or return 0; | |
1364 | my \$filenum = <FH>; | |
1365 | close FH; | |
1366 | return \$filenum == $magic_number; | |
1367 | } | |
1368 | ||
1369 | my \$progname; | |
1370 | my \$orig_dir; | |
1371 | BEGIN { | |
1372 | \$^W = 1; # Use warnings | |
1373 | \$progname = basename(\$0); | |
1374 | \$orig_dir = Cwd::cwd(); | |
1375 | my \$base_dir = '$q{base_dir}'; | |
1376 | if (!magic_number_matches()) { | |
1377 | unless (chdir(\$base_dir)) { | |
1378 | die ("Couldn't chdir(\$base_dir), aborting\\n"); | |
1379 | } | |
1380 | unless (magic_number_matches()) { | |
1381 | die ("Configuration seems to be out of date, please re-run 'perl Build.PL' again.\\n"); | |
1382 | } | |
1383 | } | |
1384 | unshift \@INC, | |
1385 | ( | |
1386 | $quoted_INC | |
1387 | ); | |
1388 | } | |
1389 | ||
1390 | close(*DATA) unless eof(*DATA); # ensure no open handles to this script | |
1391 | ||
1392 | use $build_package; | |
1393 | ||
1394 | # Some platforms have problems setting \$^X in shebang contexts, fix it up here | |
a314697d | 1395 | \$^X = Module::Build->find_perl_interpreter; |
bb4e9162 YST |
1396 | |
1397 | if (-e 'Build.PL' and not $build_package->up_to_date('Build.PL', \$progname)) { | |
1398 | warn "Warning: Build.PL has been altered. You may need to run 'perl Build.PL' again.\\n"; | |
1399 | } | |
1400 | ||
1401 | # This should have just enough arguments to be able to bootstrap the rest. | |
1402 | my \$build = $build_package->resume ( | |
1403 | properties => { | |
1404 | config_dir => '$q{config_dir}', | |
1405 | orig_dir => \$orig_dir, | |
1406 | }, | |
1407 | ); | |
1408 | ||
1409 | \$build->dispatch; | |
1410 | EOF | |
1411 | } | |
1412 | ||
1413 | sub create_build_script { | |
1414 | my ($self) = @_; | |
1415 | $self->write_config; | |
1416 | ||
1417 | my ($build_script, $dist_name, $dist_version) | |
1418 | = map $self->$_(), qw(build_script dist_name dist_version); | |
1419 | ||
1420 | if ( $self->delete_filetree($build_script) ) { | |
1421 | $self->log_info("Removed previous script '$build_script'\n\n"); | |
1422 | } | |
1423 | ||
1424 | $self->log_info("Creating new '$build_script' script for ", | |
1425 | "'$dist_name' version '$dist_version'\n"); | |
1426 | my $fh = IO::File->new(">$build_script") or die "Can't create '$build_script': $!"; | |
1427 | $self->print_build_script($fh); | |
1428 | close $fh; | |
1429 | ||
1430 | $self->make_executable($build_script); | |
1431 | ||
1432 | return 1; | |
1433 | } | |
1434 | ||
1435 | sub check_manifest { | |
1436 | my $self = shift; | |
1437 | return unless -e 'MANIFEST'; | |
1438 | ||
1439 | # Stolen nearly verbatim from MakeMaker. But ExtUtils::Manifest | |
1440 | # could easily be re-written into a modern Perl dialect. | |
1441 | ||
1442 | require ExtUtils::Manifest; # ExtUtils::Manifest is not warnings clean. | |
1443 | local ($^W, $ExtUtils::Manifest::Quiet) = (0,1); | |
1444 | ||
1445 | $self->log_info("Checking whether your kit is complete...\n"); | |
1446 | if (my @missed = ExtUtils::Manifest::manicheck()) { | |
1447 | $self->log_warn("WARNING: the following files are missing in your kit:\n", | |
1448 | "\t", join("\n\t", @missed), "\n", | |
1449 | "Please inform the author.\n\n"); | |
1450 | } else { | |
1451 | $self->log_info("Looks good\n\n"); | |
1452 | } | |
1453 | } | |
1454 | ||
1455 | sub dispatch { | |
1456 | my $self = shift; | |
1457 | local $self->{_completed_actions} = {}; | |
1458 | ||
1459 | if (@_) { | |
1460 | my ($action, %p) = @_; | |
1461 | my $args = $p{args} ? delete($p{args}) : {}; | |
1462 | ||
1463 | local $self->{invoked_action} = $action; | |
1464 | local $self->{args} = {%{$self->{args}}, %$args}; | |
1465 | local $self->{properties} = {%{$self->{properties}}, %p}; | |
1466 | return $self->_call_action($action); | |
1467 | } | |
1468 | ||
1469 | die "No build action specified" unless $self->{action}; | |
1470 | local $self->{invoked_action} = $self->{action}; | |
1471 | $self->_call_action($self->{action}); | |
1472 | } | |
1473 | ||
1474 | sub _call_action { | |
1475 | my ($self, $action) = @_; | |
1476 | ||
1477 | return if $self->{_completed_actions}{$action}++; | |
1478 | ||
1479 | local $self->{action} = $action; | |
1480 | my $method = "ACTION_$action"; | |
1481 | die "No action '$action' defined, try running the 'help' action.\n" unless $self->can($method); | |
1482 | return $self->$method(); | |
1483 | } | |
1484 | ||
1485 | sub cull_options { | |
1486 | my $self = shift; | |
1487 | my $specs = $self->get_options or return ({}, @_); | |
1488 | require Getopt::Long; | |
1489 | # XXX Should we let Getopt::Long handle M::B's options? That would | |
1490 | # be easy-ish to add to @specs right here, but wouldn't handle options | |
1491 | # passed without "--" as M::B currently allows. We might be able to | |
1492 | # get around this by setting the "prefix_pattern" Configure option. | |
1493 | my @specs; | |
1494 | my $args = {}; | |
1495 | # Construct the specifications for GetOptions. | |
1496 | while (my ($k, $v) = each %$specs) { | |
1497 | # Throw an error if specs conflict with our own. | |
1498 | die "Option specification '$k' conflicts with a " . ref $self | |
1499 | . " option of the same name" | |
1500 | if $self->valid_property($k); | |
1501 | push @specs, $k . (defined $v->{type} ? $v->{type} : ''); | |
1502 | push @specs, $v->{store} if exists $v->{store}; | |
1503 | $args->{$k} = $v->{default} if exists $v->{default}; | |
1504 | } | |
1505 | ||
1506 | local @ARGV = @_; # No other way to dupe Getopt::Long | |
1507 | ||
1508 | # Get the options values and return them. | |
1509 | # XXX Add option to allow users to set options? | |
1510 | if ( @specs ) { | |
1511 | Getopt::Long::Configure('pass_through'); | |
1512 | Getopt::Long::GetOptions($args, @specs); | |
1513 | } | |
1514 | ||
1515 | return $args, @ARGV; | |
1516 | } | |
1517 | ||
1518 | sub unparse_args { | |
1519 | my ($self, $args) = @_; | |
1520 | my @out; | |
1521 | while (my ($k, $v) = each %$args) { | |
1522 | push @out, (UNIVERSAL::isa($v, 'HASH') ? map {+"--$k", "$_=$v->{$_}"} keys %$v : | |
1523 | UNIVERSAL::isa($v, 'ARRAY') ? map {+"--$k", $_} @$v : | |
1524 | ("--$k", $v)); | |
1525 | } | |
1526 | return @out; | |
1527 | } | |
1528 | ||
1529 | sub args { | |
1530 | my $self = shift; | |
1531 | return wantarray ? %{ $self->{args} } : $self->{args} unless @_; | |
1532 | my $key = shift; | |
1533 | $self->{args}{$key} = shift if @_; | |
1534 | return $self->{args}{$key}; | |
1535 | } | |
1536 | ||
1537 | sub _translate_option { | |
1538 | my $self = shift; | |
1539 | my $opt = shift; | |
1540 | ||
1541 | (my $tr_opt = $opt) =~ tr/-/_/; | |
1542 | ||
1543 | return $tr_opt if grep $tr_opt =~ /^(?:no_?)?$_$/, qw( | |
1544 | create_makefile_pl | |
1545 | create_readme | |
1546 | extra_compiler_flags | |
1547 | extra_linker_flags | |
1548 | html_css | |
1549 | install_base | |
1550 | install_path | |
1551 | meta_add | |
1552 | meta_merge | |
1553 | test_files | |
1554 | use_rcfile | |
1555 | ); # normalize only selected option names | |
1556 | ||
1557 | return $opt; | |
1558 | } | |
1559 | ||
1560 | sub _read_arg { | |
1561 | my ($self, $args, $key, $val) = @_; | |
1562 | ||
1563 | $key = $self->_translate_option($key); | |
1564 | ||
1565 | if ( exists $args->{$key} ) { | |
1566 | $args->{$key} = [ $args->{$key} ] unless ref $args->{$key}; | |
1567 | push @{$args->{$key}}, $val; | |
1568 | } else { | |
1569 | $args->{$key} = $val; | |
1570 | } | |
1571 | } | |
1572 | ||
1573 | sub _optional_arg { | |
1574 | my $self = shift; | |
1575 | my $opt = shift; | |
1576 | my $argv = shift; | |
1577 | ||
1578 | $opt = $self->_translate_option($opt); | |
1579 | ||
1580 | my @bool_opts = qw( | |
1581 | build_bat | |
1582 | create_readme | |
1583 | pollute | |
1584 | quiet | |
1585 | uninst | |
1586 | use_rcfile | |
1587 | verbose | |
1588 | ); | |
1589 | ||
1590 | # inverted boolean options; eg --noverbose or --no-verbose | |
1591 | # converted to proper name & returned with false value (verbose, 0) | |
1592 | if ( grep $opt =~ /^no[-_]?$_$/, @bool_opts ) { | |
1593 | $opt =~ s/^no-?//; | |
1594 | return ($opt, 0); | |
1595 | } | |
1596 | ||
1597 | # non-boolean option; return option unchanged along with its argument | |
1598 | return ($opt, shift(@$argv)) unless grep $_ eq $opt, @bool_opts; | |
1599 | ||
1600 | # we're punting a bit here, if an option appears followed by a digit | |
1601 | # we take the digit as the argument for the option. If there is | |
1602 | # nothing that looks like a digit, we pretent the option is a flag | |
1603 | # that is being set and has no argument. | |
1604 | my $arg = 1; | |
1605 | $arg = shift(@$argv) if @$argv && $argv->[0] =~ /^\d+$/; | |
1606 | ||
1607 | return ($opt, $arg); | |
1608 | } | |
1609 | ||
1610 | sub read_args { | |
1611 | my $self = shift; | |
1612 | my ($action, @argv); | |
1613 | (my $args, @_) = $self->cull_options(@_); | |
1614 | my %args = %$args; | |
1615 | ||
1616 | my $opt_re = qr/[\w\-]+/; | |
1617 | ||
1618 | while (@_) { | |
1619 | local $_ = shift; | |
1620 | if ( /^(?:--)?($opt_re)=(.*)$/ ) { | |
1621 | $self->_read_arg(\%args, $1, $2); | |
1622 | } elsif ( /^--($opt_re)$/ ) { | |
1623 | my($opt, $arg) = $self->_optional_arg($1, \@_); | |
1624 | $self->_read_arg(\%args, $opt, $arg); | |
1625 | } elsif ( /^($opt_re)$/ and !defined($action)) { | |
1626 | $action = $1; | |
1627 | } else { | |
1628 | push @argv, $_; | |
1629 | } | |
1630 | } | |
1631 | $args{ARGV} = \@argv; | |
1632 | ||
c1d8f74e SP |
1633 | for ('extra_compiler_flags', 'extra_linker_flags') { |
1634 | $args{$_} = [ $self->split_like_shell($args{$_}) ] if exists $args{$_}; | |
1635 | } | |
1636 | ||
bb4e9162 | 1637 | # Hashify these parameters |
77e96e88 | 1638 | for ($self->hash_properties, 'config') { |
bb4e9162 YST |
1639 | next unless exists $args{$_}; |
1640 | my %hash; | |
1641 | $args{$_} ||= []; | |
1642 | $args{$_} = [ $args{$_} ] unless ref $args{$_}; | |
1643 | foreach my $arg ( @{$args{$_}} ) { | |
1644 | $arg =~ /(\w+)=(.*)/ | |
1645 | or die "Malformed '$_' argument: '$arg' should be something like 'foo=bar'"; | |
1646 | $hash{$1} = $2; | |
1647 | } | |
1648 | $args{$_} = \%hash; | |
1649 | } | |
1650 | ||
1651 | # De-tilde-ify any path parameters | |
1652 | for my $key (qw(prefix install_base destdir)) { | |
1653 | next if !defined $args{$key}; | |
1654 | $args{$key} = _detildefy($args{$key}); | |
1655 | } | |
1656 | ||
1657 | for my $key (qw(install_path)) { | |
1658 | next if !defined $args{$key}; | |
1659 | ||
1660 | for my $subkey (keys %{$args{$key}}) { | |
1661 | next if !defined $args{$key}{$subkey}; | |
1662 | my $subkey_ext = _detildefy($args{$key}{$subkey}); | |
1663 | if ( $subkey eq 'html' ) { # translate for compatability | |
1664 | $args{$key}{binhtml} = $subkey_ext; | |
1665 | $args{$key}{libhtml} = $subkey_ext; | |
1666 | } else { | |
1667 | $args{$key}{$subkey} = $subkey_ext; | |
1668 | } | |
1669 | } | |
1670 | } | |
1671 | ||
1672 | if ($args{makefile_env_macros}) { | |
1673 | require Module::Build::Compat; | |
1674 | %args = (%args, Module::Build::Compat->makefile_to_build_macros); | |
1675 | } | |
1676 | ||
1677 | return \%args, $action; | |
1678 | } | |
1679 | ||
1680 | ||
c1d8f74e SP |
1681 | # (bash shell won't expand tildes mid-word: "--foo=~/thing") |
1682 | # TODO: handle ~user/foo | |
bb4e9162 YST |
1683 | sub _detildefy { |
1684 | my $arg = shift; | |
1685 | ||
77e96e88 | 1686 | return $arg =~ /^~/ ? (glob $arg)[0] : $arg; |
bb4e9162 YST |
1687 | } |
1688 | ||
1689 | ||
1690 | # merge Module::Build argument lists that have already been parsed | |
1691 | # by read_args(). Takes two references to option hashes and merges | |
1692 | # the contents, giving priority to the first. | |
1693 | sub _merge_arglist { | |
1694 | my( $self, $opts1, $opts2 ) = @_; | |
1695 | ||
1696 | my %new_opts = %$opts1; | |
1697 | while (my ($key, $val) = each %$opts2) { | |
1698 | if ( exists( $opts1->{$key} ) ) { | |
1699 | if ( ref( $val ) eq 'HASH' ) { | |
1700 | while (my ($k, $v) = each %$val) { | |
1701 | $new_opts{$key}{$k} = $v unless exists( $opts1->{$key}{$k} ); | |
1702 | } | |
1703 | } | |
1704 | } else { | |
1705 | $new_opts{$key} = $val | |
1706 | } | |
1707 | } | |
1708 | ||
1709 | return %new_opts; | |
1710 | } | |
1711 | ||
dc8021d3 | 1712 | # Look for a home directory on various systems. |
bb4e9162 | 1713 | sub _home_dir { |
dc8021d3 SP |
1714 | my @home_dirs; |
1715 | push( @home_dirs, $ENV{HOME} ) if $ENV{HOME}; | |
1716 | ||
1717 | push( @home_dirs, File::Spec->catpath($ENV{HOMEDRIVE}, $ENV{HOMEPATH}, '') ) | |
1718 | if $ENV{HOMEDRIVE} && $ENV{HOMEPATH}; | |
1719 | ||
1720 | my @other_home_envs = qw( USERPROFILE APPDATA WINDIR SYS$LOGIN ); | |
1721 | push( @home_dirs, map $ENV{$_}, grep $ENV{$_}, @other_home_envs ); | |
1722 | ||
1723 | my @real_home_dirs = grep -d, @home_dirs; | |
1724 | ||
1725 | return wantarray ? @real_home_dirs : shift( @real_home_dirs ); | |
1726 | } | |
1727 | ||
1728 | sub _find_user_config { | |
1729 | my $self = shift; | |
1730 | my $file = shift; | |
1731 | foreach my $dir ( $self->_home_dir ) { | |
1732 | my $path = File::Spec->catfile( $dir, $file ); | |
1733 | return $path if -e $path; | |
bb4e9162 | 1734 | } |
dc8021d3 | 1735 | return undef; |
bb4e9162 YST |
1736 | } |
1737 | ||
1738 | # read ~/.modulebuildrc returning global options '*' and | |
1739 | # options specific to the currently executing $action. | |
1740 | sub read_modulebuildrc { | |
1741 | my( $self, $action ) = @_; | |
1742 | ||
1743 | return () unless $self->use_rcfile; | |
1744 | ||
1745 | my $modulebuildrc; | |
1746 | if ( exists($ENV{MODULEBUILDRC}) && $ENV{MODULEBUILDRC} eq 'NONE' ) { | |
1747 | return (); | |
1748 | } elsif ( exists($ENV{MODULEBUILDRC}) && -e $ENV{MODULEBUILDRC} ) { | |
1749 | $modulebuildrc = $ENV{MODULEBUILDRC}; | |
1750 | } elsif ( exists($ENV{MODULEBUILDRC}) ) { | |
1751 | $self->log_warn("WARNING: Can't find resource file " . | |
1752 | "'$ENV{MODULEBUILDRC}' defined in environment.\n" . | |
1753 | "No options loaded\n"); | |
1754 | return (); | |
1755 | } else { | |
dc8021d3 SP |
1756 | $modulebuildrc = $self->_find_user_config( '.modulebuildrc' ); |
1757 | return () unless $modulebuildrc; | |
bb4e9162 YST |
1758 | } |
1759 | ||
1760 | my $fh = IO::File->new( $modulebuildrc ) | |
1761 | or die "Can't open $modulebuildrc: $!"; | |
1762 | ||
1763 | my %options; my $buffer = ''; | |
1764 | while (defined( my $line = <$fh> )) { | |
1765 | chomp( $line ); | |
1766 | $line =~ s/#.*$//; | |
1767 | next unless length( $line ); | |
1768 | ||
1769 | if ( $line =~ /^\S/ ) { | |
1770 | if ( $buffer ) { | |
1771 | my( $action, $options ) = split( /\s+/, $buffer, 2 ); | |
1772 | $options{$action} .= $options . ' '; | |
1773 | $buffer = ''; | |
1774 | } | |
1775 | $buffer = $line; | |
1776 | } else { | |
1777 | $buffer .= $line; | |
1778 | } | |
1779 | } | |
1780 | ||
1781 | if ( $buffer ) { # anything left in $buffer ? | |
1782 | my( $action, $options ) = split( /\s+/, $buffer, 2 ); | |
1783 | $options{$action} .= $options . ' '; # merge if more than one line | |
1784 | } | |
1785 | ||
1786 | my ($global_opts) = | |
1787 | $self->read_args( $self->split_like_shell( $options{'*'} || '' ) ); | |
1788 | my ($action_opts) = | |
1789 | $self->read_args( $self->split_like_shell( $options{$action} || '' ) ); | |
1790 | ||
1791 | # specific $action options take priority over global options '*' | |
1792 | return $self->_merge_arglist( $action_opts, $global_opts ); | |
1793 | } | |
1794 | ||
1795 | # merge the relevant options in ~/.modulebuildrc into Module::Build's | |
1796 | # option list where they do not conflict with commandline options. | |
1797 | sub merge_modulebuildrc { | |
1798 | my( $self, $action, %cmdline_opts ) = @_; | |
1799 | my %rc_opts = $self->read_modulebuildrc( $action || $self->{action} || 'build' ); | |
1800 | my %new_opts = $self->_merge_arglist( \%cmdline_opts, \%rc_opts ); | |
1801 | $self->merge_args( $action, %new_opts ); | |
1802 | } | |
1803 | ||
1804 | sub merge_args { | |
1805 | my ($self, $action, %args) = @_; | |
1806 | $self->{action} = $action if defined $action; | |
1807 | ||
1808 | my %additive = map { $_ => 1 } $self->hash_properties; | |
1809 | ||
1810 | # Extract our 'properties' from $cmd_args, the rest are put in 'args'. | |
1811 | while (my ($key, $val) = each %args) { | |
1812 | $self->{phash}{runtime_params}->access( $key => $val ) | |
1813 | if $self->valid_property($key); | |
bb4e9162 | 1814 | |
77e96e88 RGS |
1815 | if ($key eq 'config') { |
1816 | $self->config($_ => $val->{$_}) foreach keys %$val; | |
bb4e9162 | 1817 | } else { |
77e96e88 RGS |
1818 | my $add_to = ( $additive{$key} ? $self->{properties}{$key} |
1819 | : $self->valid_property($key) ? $self->{properties} | |
1820 | : $self->{args}); | |
1821 | ||
1822 | if ($additive{$key}) { | |
1823 | $add_to->{$_} = $val->{$_} foreach keys %$val; | |
1824 | } else { | |
1825 | $add_to->{$key} = $val; | |
1826 | } | |
bb4e9162 YST |
1827 | } |
1828 | } | |
1829 | } | |
1830 | ||
1831 | sub cull_args { | |
1832 | my $self = shift; | |
1833 | my ($args, $action) = $self->read_args(@_); | |
1834 | $self->merge_args($action, %$args); | |
1835 | $self->merge_modulebuildrc( $action, %$args ); | |
1836 | } | |
1837 | ||
1838 | sub super_classes { | |
1839 | my ($self, $class, $seen) = @_; | |
1840 | $class ||= ref($self) || $self; | |
1841 | $seen ||= {}; | |
1842 | ||
1843 | no strict 'refs'; | |
1844 | my @super = grep {not $seen->{$_}++} $class, @{ $class . '::ISA' }; | |
1845 | return @super, map {$self->super_classes($_,$seen)} @super; | |
1846 | } | |
1847 | ||
1848 | sub known_actions { | |
1849 | my ($self) = @_; | |
1850 | ||
1851 | my %actions; | |
1852 | no strict 'refs'; | |
1853 | ||
1854 | foreach my $class ($self->super_classes) { | |
1855 | foreach ( keys %{ $class . '::' } ) { | |
1856 | $actions{$1}++ if /^ACTION_(\w+)/; | |
1857 | } | |
1858 | } | |
1859 | ||
1860 | return wantarray ? sort keys %actions : \%actions; | |
1861 | } | |
1862 | ||
1863 | sub get_action_docs { | |
7253302f SP |
1864 | my ($self, $action) = @_; |
1865 | my $actions = $self->known_actions; | |
1866 | die "No known action '$action'" unless $actions->{$action}; | |
1867 | ||
bb4e9162 YST |
1868 | my ($files_found, @docs) = (0); |
1869 | foreach my $class ($self->super_classes) { | |
1870 | (my $file = $class) =~ s{::}{/}g; | |
c1d8f74e | 1871 | # NOTE: silently skipping relative paths if any chdir() happened |
bb4e9162 YST |
1872 | $file = $INC{$file . '.pm'} or next; |
1873 | my $fh = IO::File->new("< $file") or next; | |
1874 | $files_found++; | |
7253302f | 1875 | |
bb4e9162 | 1876 | # Code below modified from /usr/bin/perldoc |
7253302f | 1877 | |
bb4e9162 YST |
1878 | # Skip to ACTIONS section |
1879 | local $_; | |
1880 | while (<$fh>) { | |
1881 | last if /^=head1 ACTIONS\s/; | |
1882 | } | |
7253302f | 1883 | |
c1d8f74e SP |
1884 | # Look for our action and determine the style |
1885 | my $style; | |
bb4e9162 | 1886 | while (<$fh>) { |
c1d8f74e SP |
1887 | last if /^=head1 /; |
1888 | ||
1889 | # only item and head2 are allowed (3&4 are not in 5.005) | |
1890 | if(/^=(item|head2)\s+\Q$action\E\b/) { | |
1891 | $style = $1; | |
1892 | push @docs, $_; | |
1893 | last; | |
bb4e9162 | 1894 | } |
bb4e9162 | 1895 | } |
c1d8f74e SP |
1896 | $style or next; # not here |
1897 | ||
1898 | # and the content | |
1899 | if($style eq 'item') { | |
1900 | my ($found, $inlist) = (0, 0); | |
1901 | while (<$fh>) { | |
1902 | if (/^=(item|back)/) { | |
1903 | last unless $inlist; | |
1904 | } | |
1905 | push @docs, $_; | |
1906 | ++$inlist if /^=over/; | |
1907 | --$inlist if /^=back/; | |
1908 | } | |
1909 | } | |
1910 | else { # head2 style | |
1911 | # stop at anything equal or greater than the found level | |
1912 | while (<$fh>) { | |
1913 | last if(/^=(?:head[12]|cut)/); | |
1914 | push @docs, $_; | |
1915 | } | |
1916 | } | |
1917 | # TODO maybe disallow overriding just pod for an action | |
1918 | # TODO and possibly: @docs and last; | |
bb4e9162 YST |
1919 | } |
1920 | ||
1921 | unless ($files_found) { | |
1922 | $@ = "Couldn't find any documentation to search"; | |
1923 | return; | |
1924 | } | |
1925 | unless (@docs) { | |
1926 | $@ = "Couldn't find any docs for action '$action'"; | |
1927 | return; | |
1928 | } | |
1929 | ||
1930 | return join '', @docs; | |
1931 | } | |
1932 | ||
1933 | sub ACTION_prereq_report { | |
1934 | my $self = shift; | |
1935 | $self->log_info( $self->prereq_report ); | |
1936 | } | |
1937 | ||
1938 | sub prereq_report { | |
1939 | my $self = shift; | |
1940 | my @types = @{ $self->prereq_action_types }; | |
1941 | my $info = { map { $_ => $self->$_() } @types }; | |
1942 | ||
1943 | my $output = ''; | |
1944 | foreach my $type (@types) { | |
1945 | my $prereqs = $info->{$type}; | |
1946 | next unless %$prereqs; | |
1947 | $output .= "\n$type:\n"; | |
1948 | my $mod_len = 2; | |
1949 | my $ver_len = 4; | |
1950 | my %mods; | |
1951 | while ( my ($modname, $spec) = each %$prereqs ) { | |
1952 | my $len = length $modname; | |
1953 | $mod_len = $len if $len > $mod_len; | |
1954 | $spec ||= '0'; | |
1955 | $len = length $spec; | |
1956 | $ver_len = $len if $len > $ver_len; | |
1957 | ||
1958 | my $mod = $self->check_installed_status($modname, $spec); | |
1959 | $mod->{name} = $modname; | |
1960 | $mod->{ok} ||= 0; | |
1961 | $mod->{ok} = ! $mod->{ok} if $type =~ /^(\w+_)?conflicts$/; | |
1962 | ||
1963 | $mods{lc $modname} = $mod; | |
1964 | } | |
1965 | ||
1966 | my $space = q{ } x ($mod_len - 3); | |
1967 | my $vspace = q{ } x ($ver_len - 3); | |
1968 | my $sline = q{-} x ($mod_len - 3); | |
1969 | my $vline = q{-} x ($ver_len - 3); | |
1970 | my $disposition = ($type =~ /^(\w+_)?conflicts$/) ? | |
1971 | 'Clash' : 'Need'; | |
1972 | $output .= | |
1973 | " Module $space $disposition $vspace Have\n". | |
1974 | " ------$sline+------$vline-+----------\n"; | |
1975 | ||
1976 | ||
1977 | for my $k (sort keys %mods) { | |
1978 | my $mod = $mods{$k}; | |
1979 | my $space = q{ } x ($mod_len - length $k); | |
1980 | my $vspace = q{ } x ($ver_len - length $mod->{need}); | |
1981 | my $f = $mod->{ok} ? ' ' : '!'; | |
1982 | $output .= | |
1983 | " $f $mod->{name} $space $mod->{need} $vspace $mod->{have}\n"; | |
1984 | } | |
1985 | } | |
1986 | return $output; | |
1987 | } | |
1988 | ||
1989 | sub ACTION_help { | |
1990 | my ($self) = @_; | |
1991 | my $actions = $self->known_actions; | |
1992 | ||
1993 | if (@{$self->{args}{ARGV}}) { | |
7253302f SP |
1994 | my $msg = eval {$self->get_action_docs($self->{args}{ARGV}[0], $actions)}; |
1995 | print $@ ? "$@\n" : $msg; | |
bb4e9162 YST |
1996 | return; |
1997 | } | |
1998 | ||
1999 | print <<EOF; | |
2000 | ||
2001 | Usage: $0 <action> arg1=value arg2=value ... | |
2002 | Example: $0 test verbose=1 | |
2003 | ||
2004 | Actions defined: | |
2005 | EOF | |
2006 | ||
2007 | print $self->_action_listing($actions); | |
2008 | ||
2009 | print "\nRun `Build help <action>` for details on an individual action.\n"; | |
2010 | print "See `perldoc Module::Build` for complete documentation.\n"; | |
2011 | } | |
2012 | ||
2013 | sub _action_listing { | |
2014 | my ($self, $actions) = @_; | |
2015 | ||
2016 | # Flow down columns, not across rows | |
2017 | my @actions = sort keys %$actions; | |
2018 | @actions = map $actions[($_ + ($_ % 2) * @actions) / 2], 0..$#actions; | |
2019 | ||
2020 | my $out = ''; | |
2021 | while (my ($one, $two) = splice @actions, 0, 2) { | |
2022 | $out .= sprintf(" %-12s %-12s\n", $one, $two||''); | |
2023 | } | |
2024 | return $out; | |
2025 | } | |
2026 | ||
77e96e88 RGS |
2027 | sub ACTION_retest { |
2028 | my ($self) = @_; | |
2029 | ||
2030 | # Protect others against our @INC changes | |
2031 | local @INC = @INC; | |
2032 | ||
2033 | # Filter out nonsensical @INC entries - some versions of | |
2034 | # Test::Harness will really explode the number of entries here | |
2035 | @INC = grep {ref() || -d} @INC if @INC > 100; | |
2036 | ||
2037 | $self->do_tests; | |
2038 | } | |
2039 | ||
7253302f SP |
2040 | sub ACTION_testall { |
2041 | my ($self) = @_; | |
2042 | ||
2043 | my @types; | |
2044 | for my $action (grep { $_ ne 'all' } $self->get_test_types) { | |
2045 | # XXX We can't just dispatch because we get multiple summaries but | |
2046 | # we'll need to dispatch to support custom setup/teardown in the | |
2047 | # action. To support that, we'll need to call something besides | |
2048 | # Harness::runtests() because we'll need to collect the results in | |
2049 | # parts, then run the summary. | |
2050 | push(@types, $action); | |
2051 | #$self->_call_action( "test$action" ); | |
2052 | } | |
2053 | $self->generic_test(types => ['default', @types]); | |
2054 | } | |
2055 | ||
2056 | sub get_test_types { | |
2057 | my ($self) = @_; | |
2058 | ||
2059 | my $t = $self->{properties}->{test_types}; | |
2060 | return ( defined $t ? ( keys %$t ) : () ); | |
2061 | } | |
2062 | ||
77e96e88 | 2063 | |
bb4e9162 YST |
2064 | sub ACTION_test { |
2065 | my ($self) = @_; | |
7253302f SP |
2066 | $self->generic_test(type => 'default'); |
2067 | } | |
2068 | ||
2069 | sub generic_test { | |
2070 | my $self = shift; | |
2071 | (@_ % 2) and croak('Odd number of elements in argument hash'); | |
2072 | my %args = @_; | |
2073 | ||
bb4e9162 | 2074 | my $p = $self->{properties}; |
7253302f SP |
2075 | |
2076 | my @types = ( | |
2077 | (exists($args{type}) ? $args{type} : ()), | |
2078 | (exists($args{types}) ? @{$args{types}} : ()), | |
2079 | ); | |
2080 | @types or croak "need some types of tests to check"; | |
2081 | ||
2082 | my %test_types = ( | |
2083 | default => '.t', | |
2084 | (defined($p->{test_types}) ? %{$p->{test_types}} : ()), | |
2085 | ); | |
2086 | ||
2087 | for my $type (@types) { | |
2088 | croak "$type not defined in test_types!" | |
2089 | unless defined $test_types{ $type }; | |
2090 | } | |
2091 | ||
2092 | # we use local here because it ends up two method calls deep | |
2093 | local $p->{test_file_exts} = [ @test_types{@types} ]; | |
bb4e9162 | 2094 | $self->depends_on('code'); |
7253302f | 2095 | |
77e96e88 RGS |
2096 | # Protect others against our @INC changes |
2097 | local @INC = @INC; | |
2098 | ||
2099 | # Make sure we test the module in blib/ | |
2100 | unshift @INC, (File::Spec->catdir($p->{base_dir}, $self->blib, 'lib'), | |
2101 | File::Spec->catdir($p->{base_dir}, $self->blib, 'arch')); | |
2102 | ||
2103 | # Filter out nonsensical @INC entries - some versions of | |
2104 | # Test::Harness will really explode the number of entries here | |
2105 | @INC = grep {ref() || -d} @INC if @INC > 100; | |
2106 | ||
2107 | $self->do_tests; | |
2108 | } | |
2109 | ||
2110 | sub do_tests { | |
2111 | my $self = shift; | |
2112 | my $p = $self->{properties}; | |
2113 | require Test::Harness; | |
2114 | ||
bb4e9162 YST |
2115 | # Do everything in our power to work with all versions of Test::Harness |
2116 | my @harness_switches = $p->{debugger} ? qw(-w -d) : (); | |
2117 | local $Test::Harness::switches = join ' ', grep defined, $Test::Harness::switches, @harness_switches; | |
2118 | local $Test::Harness::Switches = join ' ', grep defined, $Test::Harness::Switches, @harness_switches; | |
2119 | local $ENV{HARNESS_PERL_SWITCHES} = join ' ', grep defined, $ENV{HARNESS_PERL_SWITCHES}, @harness_switches; | |
2120 | ||
2121 | $Test::Harness::switches = undef unless length $Test::Harness::switches; | |
2122 | $Test::Harness::Switches = undef unless length $Test::Harness::Switches; | |
2123 | delete $ENV{HARNESS_PERL_SWITCHES} unless length $ENV{HARNESS_PERL_SWITCHES}; | |
2124 | ||
2125 | local ($Test::Harness::verbose, | |
2126 | $Test::Harness::Verbose, | |
2127 | $ENV{TEST_VERBOSE}, | |
2128 | $ENV{HARNESS_VERBOSE}) = ($p->{verbose} || 0) x 4; | |
2129 | ||
bb4e9162 YST |
2130 | my $tests = $self->find_test_files; |
2131 | ||
2132 | if (@$tests) { | |
2133 | # Work around a Test::Harness bug that loses the particular perl | |
2134 | # we're running under. $self->perl is trustworthy, but $^X isn't. | |
2135 | local $^X = $self->perl; | |
2136 | Test::Harness::runtests(@$tests); | |
2137 | } else { | |
2138 | $self->log_info("No tests defined.\n"); | |
2139 | } | |
2140 | ||
2141 | # This will get run and the user will see the output. It doesn't | |
2142 | # emit Test::Harness-style output. | |
2143 | if (-e 'visual.pl') { | |
2144 | $self->run_perl_script('visual.pl', '-Mblib='.$self->blib); | |
2145 | } | |
2146 | } | |
2147 | ||
2148 | sub test_files { | |
2149 | my $self = shift; | |
2150 | my $p = $self->{properties}; | |
2151 | if (@_) { | |
2152 | return $p->{test_files} = (@_ == 1 ? shift : [@_]); | |
2153 | } | |
2154 | return $self->find_test_files; | |
2155 | } | |
2156 | ||
2157 | sub expand_test_dir { | |
2158 | my ($self, $dir) = @_; | |
7253302f SP |
2159 | my $exts = $self->{properties}{test_file_exts} || ['.t']; |
2160 | ||
2161 | return sort map { @{$self->rscan_dir($dir, qr{^[^.].*\Q$_\E$})} } @$exts | |
2162 | if $self->recursive_test_files; | |
2163 | ||
2164 | return sort map { glob File::Spec->catfile($dir, "*$_") } @$exts; | |
bb4e9162 YST |
2165 | } |
2166 | ||
2167 | sub ACTION_testdb { | |
2168 | my ($self) = @_; | |
2169 | local $self->{properties}{debugger} = 1; | |
2170 | $self->depends_on('test'); | |
2171 | } | |
2172 | ||
2173 | sub ACTION_testcover { | |
2174 | my ($self) = @_; | |
2175 | ||
2176 | unless (Module::Build::ModuleInfo->find_module_by_name('Devel::Cover')) { | |
2177 | warn("Cannot run testcover action unless Devel::Cover is installed.\n"); | |
2178 | return; | |
2179 | } | |
2180 | ||
2181 | $self->add_to_cleanup('coverage', 'cover_db'); | |
2182 | $self->depends_on('code'); | |
2183 | ||
2184 | # See whether any of the *.pm files have changed since last time | |
2185 | # testcover was run. If so, start over. | |
2186 | if (-e 'cover_db') { | |
d1bd4ef0 JM |
2187 | my $pm_files = $self->rscan_dir |
2188 | (File::Spec->catdir($self->blib, 'lib'), file_qr('\.pm$') ); | |
bb4e9162 YST |
2189 | my $cover_files = $self->rscan_dir('cover_db', sub {-f $_ and not /\.html$/}); |
2190 | ||
2191 | $self->do_system(qw(cover -delete)) | |
77e96e88 RGS |
2192 | unless $self->up_to_date($pm_files, $cover_files) |
2193 | && $self->up_to_date($self->test_files, $cover_files); | |
bb4e9162 YST |
2194 | } |
2195 | ||
2196 | local $Test::Harness::switches = | |
2197 | local $Test::Harness::Switches = | |
2198 | local $ENV{HARNESS_PERL_SWITCHES} = "-MDevel::Cover"; | |
2199 | ||
2200 | $self->depends_on('test'); | |
2201 | $self->do_system('cover'); | |
2202 | } | |
2203 | ||
2204 | sub ACTION_code { | |
2205 | my ($self) = @_; | |
2206 | ||
2207 | # All installable stuff gets created in blib/ . | |
2208 | # Create blib/arch to keep blib.pm happy | |
2209 | my $blib = $self->blib; | |
2210 | $self->add_to_cleanup($blib); | |
2211 | File::Path::mkpath( File::Spec->catdir($blib, 'arch') ); | |
2212 | ||
2213 | if (my $split = $self->autosplit) { | |
2214 | $self->autosplit_file($_, $blib) for ref($split) ? @$split : ($split); | |
2215 | } | |
2216 | ||
2217 | foreach my $element (@{$self->build_elements}) { | |
2218 | my $method = "process_${element}_files"; | |
2219 | $method = "process_files_by_extension" unless $self->can($method); | |
2220 | $self->$method($element); | |
2221 | } | |
2222 | ||
2223 | $self->depends_on('config_data'); | |
2224 | } | |
2225 | ||
2226 | sub ACTION_build { | |
2227 | my $self = shift; | |
2228 | $self->depends_on('code'); | |
2229 | $self->depends_on('docs'); | |
2230 | } | |
2231 | ||
2232 | sub process_files_by_extension { | |
2233 | my ($self, $ext) = @_; | |
2234 | ||
2235 | my $method = "find_${ext}_files"; | |
2236 | my $files = $self->can($method) ? $self->$method() : $self->_find_file_by_type($ext, 'lib'); | |
2237 | ||
2238 | while (my ($file, $dest) = each %$files) { | |
2239 | $self->copy_if_modified(from => $file, to => File::Spec->catfile($self->blib, $dest) ); | |
2240 | } | |
2241 | } | |
2242 | ||
2243 | sub process_support_files { | |
2244 | my $self = shift; | |
2245 | my $p = $self->{properties}; | |
2246 | return unless $p->{c_source}; | |
2247 | ||
2248 | push @{$p->{include_dirs}}, $p->{c_source}; | |
2249 | ||
650ef4db | 2250 | my $files = $self->rscan_dir($p->{c_source}, file_qr('\.c(pp)?$')); |
bb4e9162 YST |
2251 | foreach my $file (@$files) { |
2252 | push @{$p->{objects}}, $self->compile_c($file); | |
2253 | } | |
2254 | } | |
2255 | ||
2256 | sub process_PL_files { | |
2257 | my ($self) = @_; | |
2258 | my $files = $self->find_PL_files; | |
2259 | ||
2260 | while (my ($file, $to) = each %$files) { | |
2261 | unless ($self->up_to_date( $file, $to )) { | |
2262 | $self->run_perl_script($file, [], [@$to]); | |
2263 | $self->add_to_cleanup(@$to); | |
2264 | } | |
2265 | } | |
2266 | } | |
2267 | ||
2268 | sub process_xs_files { | |
2269 | my $self = shift; | |
2270 | my $files = $self->find_xs_files; | |
2271 | while (my ($from, $to) = each %$files) { | |
2272 | unless ($from eq $to) { | |
2273 | $self->add_to_cleanup($to); | |
2274 | $self->copy_if_modified( from => $from, to => $to ); | |
2275 | } | |
2276 | $self->process_xs($to); | |
2277 | } | |
2278 | } | |
2279 | ||
2280 | sub process_pod_files { shift()->process_files_by_extension(shift()) } | |
2281 | sub process_pm_files { shift()->process_files_by_extension(shift()) } | |
2282 | ||
2283 | sub process_script_files { | |
2284 | my $self = shift; | |
2285 | my $files = $self->find_script_files; | |
2286 | return unless keys %$files; | |
2287 | ||
2288 | my $script_dir = File::Spec->catdir($self->blib, 'script'); | |
2289 | File::Path::mkpath( $script_dir ); | |
2290 | ||
2291 | foreach my $file (keys %$files) { | |
2292 | my $result = $self->copy_if_modified($file, $script_dir, 'flatten') or next; | |
c1d8f74e | 2293 | $self->fix_shebang_line($result) unless $self->is_vmsish; |
bb4e9162 YST |
2294 | $self->make_executable($result); |
2295 | } | |
2296 | } | |
2297 | ||
2298 | sub find_PL_files { | |
2299 | my $self = shift; | |
2300 | if (my $files = $self->{properties}{PL_files}) { | |
2301 | # 'PL_files' is given as a Unix file spec, so we localize_file_path(). | |
2302 | ||
2303 | if (UNIVERSAL::isa($files, 'ARRAY')) { | |
2304 | return { map {$_, [/^(.*)\.PL$/]} | |
2305 | map $self->localize_file_path($_), | |
2306 | @$files }; | |
2307 | ||
2308 | } elsif (UNIVERSAL::isa($files, 'HASH')) { | |
2309 | my %out; | |
2310 | while (my ($file, $to) = each %$files) { | |
2311 | $out{ $self->localize_file_path($file) } = [ map $self->localize_file_path($_), | |
2312 | ref $to ? @$to : ($to) ]; | |
2313 | } | |
2314 | return \%out; | |
2315 | ||
2316 | } else { | |
2317 | die "'PL_files' must be a hash reference or array reference"; | |
2318 | } | |
2319 | } | |
2320 | ||
2321 | return unless -d 'lib'; | |
d1bd4ef0 JM |
2322 | return { map {$_, [/^(.*)\.PL$/i ]} @{ $self->rscan_dir('lib', |
2323 | file_qr('\.PL$')) } }; | |
bb4e9162 YST |
2324 | } |
2325 | ||
2326 | sub find_pm_files { shift->_find_file_by_type('pm', 'lib') } | |
2327 | sub find_pod_files { shift->_find_file_by_type('pod', 'lib') } | |
2328 | sub find_xs_files { shift->_find_file_by_type('xs', 'lib') } | |
2329 | ||
2330 | sub find_script_files { | |
2331 | my $self = shift; | |
2332 | if (my $files = $self->script_files) { | |
2333 | # Always given as a Unix file spec. Values in the hash are | |
2334 | # meaningless, but we preserve if present. | |
2335 | return { map {$self->localize_file_path($_), $files->{$_}} keys %$files }; | |
2336 | } | |
2337 | ||
2338 | # No default location for script files | |
2339 | return {}; | |
2340 | } | |
2341 | ||
2342 | sub find_test_files { | |
2343 | my $self = shift; | |
2344 | my $p = $self->{properties}; | |
7253302f | 2345 | |
bb4e9162 YST |
2346 | if (my $files = $p->{test_files}) { |
2347 | $files = [keys %$files] if UNIVERSAL::isa($files, 'HASH'); | |
2348 | $files = [map { -d $_ ? $self->expand_test_dir($_) : $_ } | |
2349 | map glob, | |
2350 | $self->split_like_shell($files)]; | |
2351 | ||
2352 | # Always given as a Unix file spec. | |
2353 | return [ map $self->localize_file_path($_), @$files ]; | |
2354 | ||
2355 | } else { | |
2356 | # Find all possible tests in t/ or test.pl | |
2357 | my @tests; | |
2358 | push @tests, 'test.pl' if -e 'test.pl'; | |
2359 | push @tests, $self->expand_test_dir('t') if -e 't' and -d _; | |
2360 | return \@tests; | |
2361 | } | |
2362 | } | |
2363 | ||
2364 | sub _find_file_by_type { | |
2365 | my ($self, $type, $dir) = @_; | |
2366 | ||
2367 | if (my $files = $self->{properties}{"${type}_files"}) { | |
2368 | # Always given as a Unix file spec | |
2369 | return { map $self->localize_file_path($_), %$files }; | |
2370 | } | |
2371 | ||
2372 | return {} unless -d $dir; | |
2373 | return { map {$_, $_} | |
2374 | map $self->localize_file_path($_), | |
2375 | grep !/\.\#/, | |
d1bd4ef0 | 2376 | @{ $self->rscan_dir($dir, file_qr("\\.$type\$")) } }; |
bb4e9162 YST |
2377 | } |
2378 | ||
2379 | sub localize_file_path { | |
2380 | my ($self, $path) = @_; | |
c1d8f74e | 2381 | $path =~ s/\.\z// if $self->is_vmsish; |
bb4e9162 YST |
2382 | return File::Spec->catfile( split m{/}, $path ); |
2383 | } | |
2384 | ||
2385 | sub localize_dir_path { | |
2386 | my ($self, $path) = @_; | |
2387 | return File::Spec->catdir( split m{/}, $path ); | |
2388 | } | |
2389 | ||
2390 | sub fix_shebang_line { # Adapted from fixin() in ExtUtils::MM_Unix 1.35 | |
2391 | my ($self, @files) = @_; | |
77e96e88 | 2392 | my $c = ref($self) ? $self->{config} : 'Module::Build::Config'; |
bb4e9162 | 2393 | |
77e96e88 | 2394 | my ($does_shbang) = $c->get('sharpbang') =~ /^\s*\#\!/; |
bb4e9162 YST |
2395 | for my $file (@files) { |
2396 | my $FIXIN = IO::File->new($file) or die "Can't process '$file': $!"; | |
2397 | local $/ = "\n"; | |
2398 | chomp(my $line = <$FIXIN>); | |
2399 | next unless $line =~ s/^\s*\#!\s*//; # Not a shbang file. | |
2400 | ||
2401 | my ($cmd, $arg) = (split(' ', $line, 2), ''); | |
2402 | next unless $cmd =~ /perl/i; | |
2403 | my $interpreter = $self->{properties}{perl}; | |
2404 | ||
2405 | $self->log_verbose("Changing sharpbang in $file to $interpreter"); | |
2406 | my $shb = ''; | |
77e96e88 | 2407 | $shb .= $c->get('sharpbang')."$interpreter $arg\n" if $does_shbang; |
bb4e9162 YST |
2408 | |
2409 | # I'm not smart enough to know the ramifications of changing the | |
2410 | # embedded newlines here to \n, so I leave 'em in. | |
2411 | $shb .= qq{ | |
2412 | eval 'exec $interpreter $arg -S \$0 \${1+"\$\@"}' | |
2413 | if 0; # not running under some shell | |
c1d8f74e | 2414 | } unless $self->is_windowsish; # this won't work on win32, so don't |
bb4e9162 YST |
2415 | |
2416 | my $FIXOUT = IO::File->new(">$file.new") | |
2417 | or die "Can't create new $file: $!\n"; | |
2418 | ||
2419 | # Print out the new #! line (or equivalent). | |
2420 | local $\; | |
2421 | undef $/; # Was localized above | |
2422 | print $FIXOUT $shb, <$FIXIN>; | |
2423 | close $FIXIN; | |
2424 | close $FIXOUT; | |
2425 | ||
2426 | rename($file, "$file.bak") | |
2427 | or die "Can't rename $file to $file.bak: $!"; | |
2428 | ||
2429 | rename("$file.new", $file) | |
2430 | or die "Can't rename $file.new to $file: $!"; | |
2431 | ||
7253302f | 2432 | $self->delete_filetree("$file.bak") |
bb4e9162 YST |
2433 | or $self->log_warn("Couldn't clean up $file.bak, leaving it there"); |
2434 | ||
77e96e88 | 2435 | $self->do_system($c->get('eunicefix'), $file) if $c->get('eunicefix') ne ':'; |
bb4e9162 YST |
2436 | } |
2437 | } | |
2438 | ||
2439 | ||
2440 | sub ACTION_testpod { | |
2441 | my $self = shift; | |
2442 | $self->depends_on('docs'); | |
2443 | ||
2444 | eval q{use Test::Pod 0.95; 1} | |
2445 | or die "The 'testpod' action requires Test::Pod version 0.95"; | |
2446 | ||
2447 | my @files = sort keys %{$self->_find_pods($self->libdoc_dirs)}, | |
d1bd4ef0 JM |
2448 | keys %{$self->_find_pods |
2449 | ($self->bindoc_dirs, | |
2450 | exclude => [ file_qr('\.bat$') ])} | |
bb4e9162 YST |
2451 | or die "Couldn't find any POD files to test\n"; |
2452 | ||
2453 | { package Module::Build::PodTester; # Don't want to pollute the main namespace | |
2454 | Test::Pod->import( tests => scalar @files ); | |
2455 | pod_file_ok($_) foreach @files; | |
2456 | } | |
2457 | } | |
2458 | ||
47f13fd5 SP |
2459 | sub ACTION_testpodcoverage { |
2460 | my $self = shift; | |
2461 | ||
2462 | $self->depends_on('docs'); | |
2463 | ||
2464 | eval q{use Test::Pod::Coverage 1.00; 1} | |
2465 | or die "The 'testpodcoverage' action requires ", | |
2466 | "Test::Pod::Coverage version 1.00"; | |
2467 | ||
c1d8f74e SP |
2468 | # TODO this needs test coverage! |
2469 | ||
2470 | # XXX work-around a bug in Test::Pod::Coverage previous to v1.09 | |
2471 | # Make sure we test the module in blib/ | |
2472 | local @INC = @INC; | |
2473 | my $p = $self->{properties}; | |
2474 | unshift(@INC, | |
2475 | # XXX any reason to include arch? | |
2476 | File::Spec->catdir($p->{base_dir}, $self->blib, 'lib'), | |
2477 | #File::Spec->catdir($p->{base_dir}, $self->blib, 'arch') | |
2478 | ); | |
2479 | ||
47f13fd5 SP |
2480 | all_pod_coverage_ok(); |
2481 | } | |
2482 | ||
bb4e9162 YST |
2483 | sub ACTION_docs { |
2484 | my $self = shift; | |
2485 | ||
2486 | $self->depends_on('code'); | |
2487 | $self->depends_on('manpages', 'html'); | |
2488 | } | |
2489 | ||
2490 | # Given a file type, will return true if the file type would normally | |
2491 | # be installed when neither install-base nor prefix has been set. | |
2492 | # I.e. it will be true only if the path is set from Config.pm or | |
2493 | # set explicitly by the user via install-path. | |
2494 | sub _is_default_installable { | |
2495 | my $self = shift; | |
2496 | my $type = shift; | |
2497 | return ( $self->install_destination($type) && | |
2498 | ( $self->install_path($type) || | |
2499 | $self->install_sets($self->installdirs)->{$type} ) | |
2500 | ) ? 1 : 0; | |
2501 | } | |
2502 | ||
2503 | sub ACTION_manpages { | |
2504 | my $self = shift; | |
2505 | ||
2506 | return unless $self->_mb_feature('manpage_support'); | |
2507 | ||
2508 | $self->depends_on('code'); | |
2509 | ||
2510 | foreach my $type ( qw(bin lib) ) { | |
2511 | my $files = $self->_find_pods( $self->{properties}{"${type}doc_dirs"}, | |
d1bd4ef0 | 2512 | exclude => [ file_qr('\.bat$') ] ); |
bb4e9162 YST |
2513 | next unless %$files; |
2514 | ||
2515 | my $sub = $self->can("manify_${type}_pods"); | |
2516 | next unless defined( $sub ); | |
2517 | ||
2518 | if ( $self->invoked_action eq 'manpages' ) { | |
2519 | $self->$sub(); | |
2520 | } elsif ( $self->_is_default_installable("${type}doc") ) { | |
2521 | $self->$sub(); | |
2522 | } | |
2523 | } | |
2524 | ||
2525 | } | |
2526 | ||
2527 | sub manify_bin_pods { | |
2528 | my $self = shift; | |
2529 | ||
2530 | my $files = $self->_find_pods( $self->{properties}{bindoc_dirs}, | |
d1bd4ef0 | 2531 | exclude => [ file_qr('\.bat$') ] ); |
bb4e9162 YST |
2532 | return unless keys %$files; |
2533 | ||
2534 | my $mandir = File::Spec->catdir( $self->blib, 'bindoc' ); | |
77e96e88 | 2535 | File::Path::mkpath( $mandir, 0, oct(777) ); |
bb4e9162 YST |
2536 | |
2537 | require Pod::Man; | |
2538 | foreach my $file (keys %$files) { | |
2539 | # Pod::Simple based parsers only support one document per instance. | |
2540 | # This is expected to change in a future version (Pod::Simple > 3.03). | |
2541 | my $parser = Pod::Man->new( section => 1 ); # binaries go in section 1 | |
2542 | my $manpage = $self->man1page_name( $file ) . '.' . | |
2543 | $self->config( 'man1ext' ); | |
2544 | my $outfile = File::Spec->catfile($mandir, $manpage); | |
2545 | next if $self->up_to_date( $file, $outfile ); | |
2546 | $self->log_info("Manifying $file -> $outfile\n"); | |
2547 | $parser->parse_from_file( $file, $outfile ); | |
2548 | $files->{$file} = $outfile; | |
2549 | } | |
2550 | } | |
2551 | ||
2552 | sub manify_lib_pods { | |
2553 | my $self = shift; | |
2554 | ||
2555 | my $files = $self->_find_pods($self->{properties}{libdoc_dirs}); | |
2556 | return unless keys %$files; | |
2557 | ||
2558 | my $mandir = File::Spec->catdir( $self->blib, 'libdoc' ); | |
77e96e88 | 2559 | File::Path::mkpath( $mandir, 0, oct(777) ); |
bb4e9162 YST |
2560 | |
2561 | require Pod::Man; | |
2562 | while (my ($file, $relfile) = each %$files) { | |
2563 | # Pod::Simple based parsers only support one document per instance. | |
2564 | # This is expected to change in a future version (Pod::Simple > 3.03). | |
2565 | my $parser = Pod::Man->new( section => 3 ); # libraries go in section 3 | |
2566 | my $manpage = $self->man3page_name( $relfile ) . '.' . | |
2567 | $self->config( 'man3ext' ); | |
2568 | my $outfile = File::Spec->catfile( $mandir, $manpage); | |
2569 | next if $self->up_to_date( $file, $outfile ); | |
2570 | $self->log_info("Manifying $file -> $outfile\n"); | |
2571 | $parser->parse_from_file( $file, $outfile ); | |
2572 | $files->{$file} = $outfile; | |
2573 | } | |
2574 | } | |
2575 | ||
2576 | sub _find_pods { | |
2577 | my ($self, $dirs, %args) = @_; | |
2578 | my %files; | |
2579 | foreach my $spec (@$dirs) { | |
2580 | my $dir = $self->localize_dir_path($spec); | |
2581 | next unless -e $dir; | |
b3dfda33 | 2582 | |
bb4e9162 YST |
2583 | FILE: foreach my $file ( @{ $self->rscan_dir( $dir ) } ) { |
2584 | foreach my $regexp ( @{ $args{exclude} } ) { | |
2585 | next FILE if $file =~ $regexp; | |
2586 | } | |
2587 | $files{$file} = File::Spec->abs2rel($file, $dir) if $self->contains_pod( $file ) | |
2588 | } | |
2589 | } | |
2590 | return \%files; | |
2591 | } | |
2592 | ||
2593 | sub contains_pod { | |
2594 | my ($self, $file) = @_; | |
2595 | return '' unless -T $file; # Only look at text files | |
2596 | ||
2597 | my $fh = IO::File->new( $file ) or die "Can't open $file: $!"; | |
2598 | while (my $line = <$fh>) { | |
2599 | return 1 if $line =~ /^\=(?:head|pod|item)/; | |
2600 | } | |
2601 | ||
2602 | return ''; | |
2603 | } | |
2604 | ||
2605 | sub ACTION_html { | |
2606 | my $self = shift; | |
2607 | ||
2608 | return unless $self->_mb_feature('HTML_support'); | |
2609 | ||
2610 | $self->depends_on('code'); | |
2611 | ||
2612 | foreach my $type ( qw(bin lib) ) { | |
2613 | my $files = $self->_find_pods( $self->{properties}{"${type}doc_dirs"}, | |
d1bd4ef0 JM |
2614 | exclude => |
2615 | [ file_qr('\.(?:bat|com|html)$') ] ); | |
bb4e9162 YST |
2616 | next unless %$files; |
2617 | ||
2618 | if ( $self->invoked_action eq 'html' ) { | |
2619 | $self->htmlify_pods( $type ); | |
2620 | } elsif ( $self->_is_default_installable("${type}html") ) { | |
2621 | $self->htmlify_pods( $type ); | |
2622 | } | |
2623 | } | |
2624 | ||
2625 | } | |
2626 | ||
2627 | ||
2628 | # 1) If it's an ActiveState perl install, we need to run | |
2629 | # ActivePerl::DocTools->UpdateTOC; | |
2630 | # 2) Links to other modules are not being generated | |
2631 | sub htmlify_pods { | |
2632 | my $self = shift; | |
2633 | my $type = shift; | |
2634 | my $htmldir = shift || File::Spec->catdir($self->blib, "${type}html"); | |
2635 | ||
2636 | require Module::Build::PodParser; | |
2637 | require Pod::Html; | |
2638 | ||
2639 | $self->add_to_cleanup('pod2htm*'); | |
2640 | ||
2641 | my $pods = $self->_find_pods( $self->{properties}{"${type}doc_dirs"}, | |
d1bd4ef0 | 2642 | exclude => [ file_qr('\.(?:bat|com|html)$') ] ); |
f943a5bf | 2643 | return unless %$pods; # nothing to do |
bb4e9162 YST |
2644 | |
2645 | unless ( -d $htmldir ) { | |
77e96e88 | 2646 | File::Path::mkpath($htmldir, 0, oct(755)) |
bb4e9162 YST |
2647 | or die "Couldn't mkdir $htmldir: $!"; |
2648 | } | |
2649 | ||
2650 | my @rootdirs = ($type eq 'bin') ? qw(bin) : | |
2651 | $self->installdirs eq 'core' ? qw(lib) : qw(site lib); | |
2652 | ||
2653 | my $podpath = join ':', | |
2654 | map $_->[1], | |
2655 | grep -e $_->[0], | |
2656 | map [File::Spec->catdir($self->blib, $_), $_], | |
2657 | qw( script lib ); | |
2658 | ||
2659 | foreach my $pod ( keys %$pods ) { | |
2660 | ||
2661 | my ($name, $path) = File::Basename::fileparse($pods->{$pod}, | |
d1bd4ef0 | 2662 | file_qr('\.(?:pm|plx?|pod)$')); |
bb4e9162 YST |
2663 | my @dirs = File::Spec->splitdir( File::Spec->canonpath( $path ) ); |
2664 | pop( @dirs ) if $dirs[-1] eq File::Spec->curdir; | |
2665 | ||
2666 | my $fulldir = File::Spec->catfile($htmldir, @rootdirs, @dirs); | |
2667 | my $outfile = File::Spec->catfile($fulldir, "${name}.html"); | |
2668 | my $infile = File::Spec->abs2rel($pod); | |
2669 | ||
2670 | next if $self->up_to_date($infile, $outfile); | |
2671 | ||
2672 | unless ( -d $fulldir ){ | |
77e96e88 | 2673 | File::Path::mkpath($fulldir, 0, oct(755)) |
bb4e9162 YST |
2674 | or die "Couldn't mkdir $fulldir: $!"; |
2675 | } | |
2676 | ||
2677 | my $path2root = join( '/', ('..') x (@rootdirs+@dirs) ); | |
2678 | my $htmlroot = join( '/', | |
2679 | ($path2root, | |
2680 | $self->installdirs eq 'core' ? () : qw(site) ) ); | |
2681 | ||
47f13fd5 | 2682 | my $fh = IO::File->new($infile) or die "Can't read $infile: $!"; |
bb4e9162 YST |
2683 | my $abstract = Module::Build::PodParser->new(fh => $fh)->get_abstract(); |
2684 | ||
2685 | my $title = join( '::', (@dirs, $name) ); | |
2686 | $title .= " - $abstract" if $abstract; | |
2687 | ||
2688 | my @opts = ( | |
2689 | '--flush', | |
2690 | "--title=$title", | |
2691 | "--podpath=$podpath", | |
2692 | "--infile=$infile", | |
2693 | "--outfile=$outfile", | |
2694 | '--podroot=' . $self->blib, | |
2695 | "--htmlroot=$htmlroot", | |
2696 | ); | |
2697 | ||
2698 | if ( eval{Pod::Html->VERSION(1.03)} ) { | |
2699 | push( @opts, ('--header', '--backlink=Back to Top') ); | |
2700 | push( @opts, "--css=$path2root/" . $self->html_css) if $self->html_css; | |
2701 | } | |
2702 | ||
2703 | $self->log_info("HTMLifying $infile -> $outfile\n"); | |
2704 | $self->log_verbose("pod2html @opts\n"); | |
2705 | Pod::Html::pod2html(@opts); # or warn "pod2html @opts failed: $!"; | |
2706 | } | |
2707 | ||
2708 | } | |
2709 | ||
2710 | # Adapted from ExtUtils::MM_Unix | |
2711 | sub man1page_name { | |
2712 | my $self = shift; | |
2713 | return File::Basename::basename( shift ); | |
2714 | } | |
2715 | ||
2716 | # Adapted from ExtUtils::MM_Unix and Pod::Man | |
2717 | # Depending on M::B's dependency policy, it might make more sense to refactor | |
2718 | # Pod::Man::begin_pod() to extract a name() methods, and use them... | |
2719 | # -spurkis | |
2720 | sub man3page_name { | |
2721 | my $self = shift; | |
2722 | my ($vol, $dirs, $file) = File::Spec->splitpath( shift ); | |
2723 | my @dirs = File::Spec->splitdir( File::Spec->canonpath($dirs) ); | |
2724 | ||
2725 | # Remove known exts from the base name | |
2726 | $file =~ s/\.p(?:od|m|l)\z//i; | |
2727 | ||
2728 | return join( $self->manpage_separator, @dirs, $file ); | |
2729 | } | |
2730 | ||
2731 | sub manpage_separator { | |
2732 | return '::'; | |
2733 | } | |
2734 | ||
2735 | # For systems that don't have 'diff' executable, should use Algorithm::Diff | |
2736 | sub ACTION_diff { | |
2737 | my $self = shift; | |
2738 | $self->depends_on('build'); | |
2739 | my $local_lib = File::Spec->rel2abs('lib'); | |
2740 | my @myINC = grep {$_ ne $local_lib} @INC; | |
2741 | ||
2742 | # The actual install destination might not be in @INC, so check there too. | |
2743 | push @myINC, map $self->install_destination($_), qw(lib arch); | |
2744 | ||
2745 | my @flags = @{$self->{args}{ARGV}}; | |
2746 | @flags = $self->split_like_shell($self->{args}{flags} || '') unless @flags; | |
2747 | ||
2748 | my $installmap = $self->install_map; | |
2749 | delete $installmap->{read}; | |
2750 | delete $installmap->{write}; | |
2751 | ||
d1bd4ef0 | 2752 | my $text_suffix = file_qr('\.(pm|pod)$'); |
bb4e9162 YST |
2753 | |
2754 | while (my $localdir = each %$installmap) { | |
2755 | my @localparts = File::Spec->splitdir($localdir); | |
2756 | my $files = $self->rscan_dir($localdir, sub {-f}); | |
2757 | ||
2758 | foreach my $file (@$files) { | |
2759 | my @parts = File::Spec->splitdir($file); | |
2760 | @parts = @parts[@localparts .. $#parts]; # Get rid of blib/lib or similar | |
2761 | ||
2762 | my $installed = Module::Build::ModuleInfo->find_module_by_name( | |
2763 | join('::', @parts), \@myINC ); | |
2764 | if (not $installed) { | |
2765 | print "Only in lib: $file\n"; | |
2766 | next; | |
2767 | } | |
2768 | ||
2769 | my $status = File::Compare::compare($installed, $file); | |
2770 | next if $status == 0; # Files are the same | |
2771 | die "Can't compare $installed and $file: $!" if $status == -1; | |
2772 | ||
2773 | if ($file =~ $text_suffix) { | |
2774 | $self->do_system('diff', @flags, $installed, $file); | |
2775 | } else { | |
2776 | print "Binary files $file and $installed differ\n"; | |
2777 | } | |
2778 | } | |
2779 | } | |
2780 | } | |
2781 | ||
2782 | sub ACTION_pure_install { | |
2783 | shift()->depends_on('install'); | |
2784 | } | |
2785 | ||
2786 | sub ACTION_install { | |
2787 | my ($self) = @_; | |
2788 | require ExtUtils::Install; | |
2789 | $self->depends_on('build'); | |
2790 | ExtUtils::Install::install($self->install_map, !$self->quiet, 0, $self->{args}{uninst}||0); | |
2791 | } | |
2792 | ||
2793 | sub ACTION_fakeinstall { | |
2794 | my ($self) = @_; | |
2795 | require ExtUtils::Install; | |
2796 | $self->depends_on('build'); | |
2797 | ExtUtils::Install::install($self->install_map, !$self->quiet, 1, $self->{args}{uninst}||0); | |
2798 | } | |
2799 | ||
2800 | sub ACTION_versioninstall { | |
2801 | my ($self) = @_; | |
2802 | ||
2803 | die "You must have only.pm 0.25 or greater installed for this operation: $@\n" | |
2804 | unless eval { require only; 'only'->VERSION(0.25); 1 }; | |
2805 | ||
2806 | $self->depends_on('build'); | |
2807 | ||
2808 | my %onlyargs = map {exists($self->{args}{$_}) ? ($_ => $self->{args}{$_}) : ()} | |
2809 | qw(version versionlib); | |
2810 | only::install::install(%onlyargs); | |
2811 | } | |
2812 | ||
2813 | sub ACTION_clean { | |
2814 | my ($self) = @_; | |
2815 | foreach my $item (map glob($_), $self->cleanup) { | |
2816 | $self->delete_filetree($item); | |
2817 | } | |
2818 | } | |
2819 | ||
2820 | sub ACTION_realclean { | |
2821 | my ($self) = @_; | |
2822 | $self->depends_on('clean'); | |
2823 | $self->delete_filetree($self->config_dir, $self->build_script); | |
2824 | } | |
2825 | ||
2826 | sub ACTION_ppd { | |
2827 | my ($self) = @_; | |
2828 | require Module::Build::PPMMaker; | |
2829 | my $ppd = Module::Build::PPMMaker->new(); | |
2830 | my $file = $ppd->make_ppd(%{$self->{args}}, build => $self); | |
2831 | $self->add_to_cleanup($file); | |
2832 | } | |
2833 | ||
2834 | sub ACTION_ppmdist { | |
2835 | my ($self) = @_; | |
2836 | ||
2837 | $self->depends_on( 'build' ); | |
2838 | ||
2839 | my $ppm = $self->ppm_name; | |
2840 | $self->delete_filetree( $ppm ); | |
2841 | $self->log_info( "Creating $ppm\n" ); | |
2842 | $self->add_to_cleanup( $ppm, "$ppm.tar.gz" ); | |
2843 | ||
2844 | my %types = ( # translate types/dirs to those expected by ppm | |
2845 | lib => 'lib', | |
2846 | arch => 'arch', | |
2847 | bin => 'bin', | |
2848 | script => 'script', | |
2849 | bindoc => 'man1', | |
2850 | libdoc => 'man3', | |
2851 | binhtml => undef, | |
2852 | libhtml => undef, | |
2853 | ); | |
2854 | ||
2855 | foreach my $type ($self->install_types) { | |
2856 | next if exists( $types{$type} ) && !defined( $types{$type} ); | |
2857 | ||
2858 | my $dir = File::Spec->catdir( $self->blib, $type ); | |
2859 | next unless -e $dir; | |
2860 | ||
2861 | my $files = $self->rscan_dir( $dir ); | |
2862 | foreach my $file ( @$files ) { | |
2863 | next unless -f $file; | |
2864 | my $rel_file = | |
2865 | File::Spec->abs2rel( File::Spec->rel2abs( $file ), | |
2866 | File::Spec->rel2abs( $dir ) ); | |
2867 | my $to_file = | |
f82d2ab4 | 2868 | File::Spec->catfile( $ppm, 'blib', |
bb4e9162 YST |
2869 | exists( $types{$type} ) ? $types{$type} : $type, |
2870 | $rel_file ); | |
2871 | $self->copy_if_modified( from => $file, to => $to_file ); | |
2872 | } | |
2873 | } | |
2874 | ||
2875 | foreach my $type ( qw(bin lib) ) { | |
2876 | local $self->{properties}{html_css} = 'Active.css'; | |
2877 | $self->htmlify_pods( $type, File::Spec->catdir($ppm, 'blib', 'html') ); | |
2878 | } | |
2879 | ||
2880 | # create a tarball; | |
2881 | # the directory tar'ed must be blib so we need to do a chdir first | |
2882 | my $start_wd = $self->cwd; | |
2883 | chdir( $ppm ) or die "Can't chdir to $ppm"; | |
2884 | $self->make_tarball( 'blib', File::Spec->catfile( $start_wd, $ppm ) ); | |
2885 | chdir( $start_wd ) or die "Can't chdir to $start_wd"; | |
2886 | ||
2887 | $self->depends_on( 'ppd' ); | |
2888 | ||
2889 | $self->delete_filetree( $ppm ); | |
2890 | } | |
2891 | ||
77e96e88 RGS |
2892 | sub ACTION_pardist { |
2893 | my ($self) = @_; | |
2894 | ||
2895 | # Need PAR::Dist | |
2896 | if ( not eval { require PAR::Dist; PAR::Dist->VERSION(0.17) } ) { | |
2897 | $self->log_warn( | |
2898 | "In order to create .par distributions, you need to\n" | |
2899 | . "install PAR::Dist first." | |
2900 | ); | |
2901 | return(); | |
2902 | } | |
2903 | ||
2904 | $self->depends_on( 'build' ); | |
2905 | ||
2906 | return PAR::Dist::blib_to_par( | |
2907 | name => $self->dist_name, | |
2908 | version => $self->dist_version, | |
2909 | ); | |
2910 | } | |
2911 | ||
bb4e9162 YST |
2912 | sub ACTION_dist { |
2913 | my ($self) = @_; | |
2914 | ||
2915 | $self->depends_on('distdir'); | |
2916 | ||
2917 | my $dist_dir = $self->dist_dir; | |
2918 | ||
2919 | $self->make_tarball($dist_dir); | |
2920 | $self->delete_filetree($dist_dir); | |
2921 | } | |
2922 | ||
2923 | sub ACTION_distcheck { | |
2924 | my ($self) = @_; | |
a314697d | 2925 | |
bb4e9162 YST |
2926 | require ExtUtils::Manifest; |
2927 | local $^W; # ExtUtils::Manifest is not warnings clean. | |
2928 | my ($missing, $extra) = ExtUtils::Manifest::fullcheck(); | |
a314697d RS |
2929 | |
2930 | return unless @$missing || @$extra; | |
2931 | ||
2932 | my $msg = "MANIFEST appears to be out of sync with the distribution\n"; | |
2933 | if ( $self->invoked_action eq 'distcheck' ) { | |
2934 | die $msg; | |
2935 | } else { | |
2936 | warn $msg; | |
2937 | } | |
bb4e9162 YST |
2938 | } |
2939 | ||
2940 | sub _add_to_manifest { | |
2941 | my ($self, $manifest, $lines) = @_; | |
2942 | $lines = [$lines] unless ref $lines; | |
2943 | ||
2944 | my $existing_files = $self->_read_manifest($manifest); | |
2945 | return unless defined( $existing_files ); | |
2946 | ||
2947 | @$lines = grep {!exists $existing_files->{$_}} @$lines | |
2948 | or return; | |
2949 | ||
2950 | my $mode = (stat $manifest)[2]; | |
77e96e88 | 2951 | chmod($mode | oct(222), $manifest) or die "Can't make $manifest writable: $!"; |
bb4e9162 YST |
2952 | |
2953 | my $fh = IO::File->new("< $manifest") or die "Can't read $manifest: $!"; | |
2954 | my $last_line = (<$fh>)[-1] || "\n"; | |
2955 | my $has_newline = $last_line =~ /\n$/; | |
2956 | $fh->close; | |
2957 | ||
2958 | $fh = IO::File->new(">> $manifest") or die "Can't write to $manifest: $!"; | |
2959 | print $fh "\n" unless $has_newline; | |
2960 | print $fh map "$_\n", @$lines; | |
2961 | close $fh; | |
2962 | chmod($mode, $manifest); | |
2963 | ||
2964 | $self->log_info(map "Added to $manifest: $_\n", @$lines); | |
2965 | } | |
2966 | ||
2967 | sub _sign_dir { | |
2968 | my ($self, $dir) = @_; | |
2969 | ||
2970 | unless (eval { require Module::Signature; 1 }) { | |
2971 | $self->log_warn("Couldn't load Module::Signature for 'distsign' action:\n $@\n"); | |
2972 | return; | |
2973 | } | |
2974 | ||
2975 | # Add SIGNATURE to the MANIFEST | |
2976 | { | |
2977 | my $manifest = File::Spec->catfile($dir, 'MANIFEST'); | |
2978 | die "Signing a distribution requires a MANIFEST file" unless -e $manifest; | |
2979 | $self->_add_to_manifest($manifest, "SIGNATURE Added here by Module::Build"); | |
2980 | } | |
2981 | ||
2982 | # We protect the signing with an eval{} to make sure we get back to | |
2983 | # the right directory after a signature failure. Would be nice if | |
2984 | # Module::Signature took a directory argument. | |
2985 | ||
2986 | my $start_dir = $self->cwd; | |
2987 | chdir $dir or die "Can't chdir() to $dir: $!"; | |
2988 | eval {local $Module::Signature::Quiet = 1; Module::Signature::sign()}; | |
2989 | my @err = $@ ? ($@) : (); | |
2990 | chdir $start_dir or push @err, "Can't chdir() back to $start_dir: $!"; | |
2991 | die join "\n", @err if @err; | |
2992 | } | |
2993 | ||
2994 | sub ACTION_distsign { | |
2995 | my ($self) = @_; | |
2996 | { | |
2997 | local $self->{properties}{sign} = 0; # We'll sign it ourselves | |
2998 | $self->depends_on('distdir') unless -d $self->dist_dir; | |
2999 | } | |
3000 | $self->_sign_dir($self->dist_dir); | |
3001 | } | |
3002 | ||
3003 | sub ACTION_skipcheck { | |
3004 | my ($self) = @_; | |
3005 | ||
3006 | require ExtUtils::Manifest; | |
3007 | local $^W; # ExtUtils::Manifest is not warnings clean. | |
3008 | ExtUtils::Manifest::skipcheck(); | |
3009 | } | |
3010 | ||
3011 | sub ACTION_distclean { | |
3012 | my ($self) = @_; | |
3013 | ||
3014 | $self->depends_on('realclean'); | |
3015 | $self->depends_on('distcheck'); | |
3016 | } | |
3017 | ||
3018 | sub do_create_makefile_pl { | |
3019 | my $self = shift; | |
3020 | require Module::Build::Compat; | |
3021 | $self->delete_filetree('Makefile.PL'); | |
3022 | $self->log_info("Creating Makefile.PL\n"); | |
3023 | Module::Build::Compat->create_makefile_pl($self->create_makefile_pl, $self, @_); | |
3024 | $self->_add_to_manifest('MANIFEST', 'Makefile.PL'); | |
3025 | } | |
3026 | ||
3027 | sub do_create_readme { | |
3028 | my $self = shift; | |
3029 | $self->delete_filetree('README'); | |
3030 | ||
3031 | my $docfile = $self->_main_docfile; | |
3032 | unless ( $docfile ) { | |
3033 | $self->log_warn(<<EOF); | |
3034 | Cannot create README: can't determine which file contains documentation; | |
3035 | Must supply either 'dist_version_from', or 'module_name' parameter. | |
3036 | EOF | |
3037 | return; | |
3038 | } | |
3039 | ||
3040 | if ( eval {require Pod::Readme; 1} ) { | |
3041 | $self->log_info("Creating README using Pod::Readme\n"); | |
3042 | ||
3043 | my $parser = Pod::Readme->new; | |
3044 | $parser->parse_from_file($docfile, 'README', @_); | |
3045 | ||
3046 | } elsif ( eval {require Pod::Text; 1} ) { | |
3047 | $self->log_info("Creating README using Pod::Text\n"); | |
3048 | ||
3049 | my $fh = IO::File->new('> README'); | |
3050 | if ( defined($fh) ) { | |
3051 | local $^W = 0; | |
3052 | no strict "refs"; | |
3053 | ||
3054 | # work around bug in Pod::Text 3.01, which expects | |
3055 | # Pod::Simple::parse_file to take input and output filehandles | |
3056 | # when it actually only takes an input filehandle | |
3057 | ||
3058 | my $old_parse_file; | |
3059 | $old_parse_file = \&{"Pod::Simple::parse_file"} | |
3060 | and | |
3061 | local *{"Pod::Simple::parse_file"} = sub { | |
3062 | my $self = shift; | |
3063 | $self->output_fh($_[1]) if $_[1]; | |
3064 | $self->$old_parse_file($_[0]); | |
3065 | } | |
3066 | if $Pod::Text::VERSION | |
3067 | == 3.01; # Split line to avoid evil version-finder | |
3068 | ||
3069 | Pod::Text::pod2text( $docfile, $fh ); | |
3070 | ||
3071 | $fh->close; | |
3072 | } else { | |
3073 | $self->log_warn( | |
3074 | "Cannot create 'README' file: Can't open file for writing\n" ); | |
3075 | return; | |
3076 | } | |
3077 | ||
3078 | } else { | |
3079 | $self->log_warn("Can't load Pod::Readme or Pod::Text to create README\n"); | |
3080 | return; | |
3081 | } | |
3082 | ||
3083 | $self->_add_to_manifest('MANIFEST', 'README'); | |
3084 | } | |
3085 | ||
3086 | sub _main_docfile { | |
3087 | my $self = shift; | |
bb4e9162 YST |
3088 | if ( my $pm_file = $self->dist_version_from ) { |
3089 | (my $pod_file = $pm_file) =~ s/.pm$/.pod/; | |
3090 | return (-e $pod_file ? $pod_file : $pm_file); | |
3091 | } else { | |
3092 | return undef; | |
3093 | } | |
3094 | } | |
3095 | ||
3096 | sub ACTION_distdir { | |
3097 | my ($self) = @_; | |
3098 | ||
3099 | $self->depends_on('distmeta'); | |
3100 | ||
3101 | my $dist_files = $self->_read_manifest('MANIFEST') | |
3102 | or die "Can't create distdir without a MANIFEST file - run 'manifest' action first"; | |
3103 | delete $dist_files->{SIGNATURE}; # Don't copy, create a fresh one | |
3104 | die "No files found in MANIFEST - try running 'manifest' action?\n" | |
3105 | unless ($dist_files and keys %$dist_files); | |
3106 | my $metafile = $self->metafile; | |
3107 | $self->log_warn("*** Did you forget to add $metafile to the MANIFEST?\n") | |
3108 | unless exists $dist_files->{$metafile}; | |
3109 | ||
3110 | my $dist_dir = $self->dist_dir; | |
3111 | $self->delete_filetree($dist_dir); | |
3112 | $self->log_info("Creating $dist_dir\n"); | |
3113 | $self->add_to_cleanup($dist_dir); | |
3114 | ||
3115 | foreach my $file (keys %$dist_files) { | |
3116 | my $new = $self->copy_if_modified(from => $file, to_dir => $dist_dir, verbose => 0); | |
bb4e9162 YST |
3117 | } |
3118 | ||
3119 | $self->_sign_dir($dist_dir) if $self->{properties}{sign}; | |
3120 | } | |
3121 | ||
3122 | sub ACTION_disttest { | |
3123 | my ($self) = @_; | |
3124 | ||
3125 | $self->depends_on('distdir'); | |
3126 | ||
3127 | my $start_dir = $self->cwd; | |
3128 | my $dist_dir = $self->dist_dir; | |
3129 | chdir $dist_dir or die "Cannot chdir to $dist_dir: $!"; | |
3130 | # XXX could be different names for scripts | |
3131 | ||
3132 | $self->run_perl_script('Build.PL') # XXX Should this be run w/ --nouse-rcfile | |
3133 | or die "Error executing 'Build.PL' in dist directory: $!"; | |
3134 | $self->run_perl_script('Build') | |
3135 | or die "Error executing 'Build' in dist directory: $!"; | |
3136 | $self->run_perl_script('Build', [], ['test']) | |
3137 | or die "Error executing 'Build test' in dist directory"; | |
3138 | chdir $start_dir; | |
3139 | } | |
3140 | ||
3141 | sub _write_default_maniskip { | |
3142 | my $self = shift; | |
3143 | my $file = shift || 'MANIFEST.SKIP'; | |
3144 | my $fh = IO::File->new("> $file") | |
3145 | or die "Can't open $file: $!"; | |
3146 | ||
3147 | # This is derived from MakeMaker's default MANIFEST.SKIP file with | |
3148 | # some new entries | |
3149 | ||
3150 | print $fh <<'EOF'; | |
3151 | # Avoid version control files. | |
3152 | \bRCS\b | |
3153 | \bCVS\b | |
3154 | ,v$ | |
3155 | \B\.svn\b | |
3156 | \B\.cvsignore$ | |
3157 | ||
3158 | # Avoid Makemaker generated and utility files. | |
3159 | \bMakefile$ | |
3160 | \bblib | |
3161 | \bMakeMaker-\d | |
3162 | \bpm_to_blib$ | |
3163 | \bblibdirs$ | |
3164 | ^MANIFEST\.SKIP$ | |
3165 | ||
3166 | # Avoid Module::Build generated and utility files. | |
3167 | \bBuild$ | |
a314697d | 3168 | \bBuild.bat$ |
bb4e9162 YST |
3169 | \b_build |
3170 | ||
3171 | # Avoid Devel::Cover generated files | |
3172 | \bcover_db | |
3173 | ||
3174 | # Avoid temp and backup files. | |
3175 | ~$ | |
3176 | \.tmp$ | |
3177 | \.old$ | |
3178 | \.bak$ | |
3179 | \#$ | |
3180 | \.# | |
3181 | \.rej$ | |
3182 | ||
3183 | # Avoid OS-specific files/dirs | |
3184 | # Mac OSX metadata | |
3185 | \B\.DS_Store | |
3186 | # Mac OSX SMB mount metadata files | |
3187 | \B\._ | |
3188 | # Avoid archives of this distribution | |
3189 | EOF | |
3190 | ||
3191 | # Skip, for example, 'Module-Build-0.27.tar.gz' | |
3192 | print $fh '\b'.$self->dist_name.'-[\d\.\_]+'."\n"; | |
3193 | ||
3194 | $fh->close(); | |
3195 | } | |
3196 | ||
3197 | sub ACTION_manifest { | |
3198 | my ($self) = @_; | |
3199 | ||
3200 | my $maniskip = 'MANIFEST.SKIP'; | |
3201 | unless ( -e 'MANIFEST' || -e $maniskip ) { | |
3202 | $self->log_warn("File '$maniskip' does not exist: Creating a default '$maniskip'\n"); | |
3203 | $self->_write_default_maniskip($maniskip); | |
3204 | } | |
3205 | ||
3206 | require ExtUtils::Manifest; # ExtUtils::Manifest is not warnings clean. | |
3207 | local ($^W, $ExtUtils::Manifest::Quiet) = (0,1); | |
3208 | ExtUtils::Manifest::mkmanifest(); | |
3209 | } | |
3210 | ||
d1bd4ef0 JM |
3211 | # Case insenstive regex for files |
3212 | sub file_qr { | |
3213 | return File::Spec->case_tolerant ? qr($_[0])i : qr($_[0]); | |
3214 | } | |
3215 | ||
bb4e9162 YST |
3216 | sub dist_dir { |
3217 | my ($self) = @_; | |
3218 | return "$self->{properties}{dist_name}-$self->{properties}{dist_version}"; | |
3219 | } | |
3220 | ||
3221 | sub ppm_name { | |
3222 | my $self = shift; | |
3223 | return 'PPM-' . $self->dist_dir; | |
3224 | } | |
3225 | ||
3226 | sub _files_in { | |
3227 | my ($self, $dir) = @_; | |
3228 | return unless -d $dir; | |
3229 | ||
3230 | local *DH; | |
3231 | opendir DH, $dir or die "Can't read directory $dir: $!"; | |
3232 | ||
3233 | my @files; | |
3234 | while (defined (my $file = readdir DH)) { | |
3235 | my $full_path = File::Spec->catfile($dir, $file); | |
3236 | next if -d $full_path; | |
3237 | push @files, $full_path; | |
3238 | } | |
3239 | return @files; | |
3240 | } | |
3241 | ||
3242 | sub script_files { | |
3243 | my $self = shift; | |
3244 | ||
3245 | for ($self->{properties}{script_files}) { | |
3246 | $_ = shift if @_; | |
3247 | next unless $_; | |
3248 | ||
3249 | # Always coerce into a hash | |
3250 | return $_ if UNIVERSAL::isa($_, 'HASH'); | |
3251 | return $_ = { map {$_,1} @$_ } if UNIVERSAL::isa($_, 'ARRAY'); | |
3252 | ||
3253 | die "'script_files' must be a hashref, arrayref, or string" if ref(); | |
3254 | ||
3255 | return $_ = { map {$_,1} $self->_files_in( $_ ) } if -d $_; | |
3256 | return $_ = {$_ => 1}; | |
3257 | } | |
3258 | ||
3259 | return $_ = { map {$_,1} $self->_files_in( File::Spec->catdir( $self->base_dir, 'bin' ) ) }; | |
3260 | } | |
3261 | BEGIN { *scripts = \&script_files; } | |
3262 | ||
3263 | { | |
3264 | my %licenses = | |
3265 | ( | |
3266 | perl => 'http://dev.perl.org/licenses/', | |
3267 | gpl => 'http://www.opensource.org/licenses/gpl-license.php', | |
3268 | apache => 'http://apache.org/licenses/LICENSE-2.0', | |
3269 | artistic => 'http://opensource.org/licenses/artistic-license.php', | |
3270 | lgpl => 'http://opensource.org/licenses/artistic-license.php', | |
3271 | bsd => 'http://www.opensource.org/licenses/bsd-license.php', | |
3272 | gpl => 'http://www.opensource.org/licenses/gpl-license.php', | |
3273 | mit => 'http://opensource.org/licenses/mit-license.php', | |
3274 | mozilla => 'http://opensource.org/licenses/mozilla1.1.php', | |
3275 | open_source => undef, | |
3276 | unrestricted => undef, | |
3277 | restrictive => undef, | |
3278 | unknown => undef, | |
3279 | ); | |
3280 | sub valid_licenses { | |
3281 | return \%licenses; | |
3282 | } | |
3283 | } | |
3284 | ||
3285 | sub _hash_merge { | |
3286 | my ($self, $h, $k, $v) = @_; | |
3287 | if (ref $h->{$k} eq 'ARRAY') { | |
3288 | push @{$h->{$k}}, ref $v ? @$v : $v; | |
3289 | } elsif (ref $h->{$k} eq 'HASH') { | |
3290 | $h->{$k}{$_} = $v->{$_} foreach keys %$v; | |
3291 | } else { | |
3292 | $h->{$k} = $v; | |
3293 | } | |
3294 | } | |
3295 | ||
bb4e9162 YST |
3296 | sub ACTION_distmeta { |
3297 | my ($self) = @_; | |
3298 | ||
3299 | $self->do_create_makefile_pl if $self->create_makefile_pl; | |
3300 | $self->do_create_readme if $self->create_readme; | |
3301 | $self->do_create_metafile; | |
3302 | } | |
3303 | ||
3304 | sub do_create_metafile { | |
3305 | my $self = shift; | |
3306 | return if $self->{wrote_metadata}; | |
3307 | ||
3308 | my $p = $self->{properties}; | |
3309 | my $metafile = $self->metafile; | |
3310 | ||
3311 | unless ($p->{license}) { | |
3312 | $self->log_warn("No license specified, setting license = 'unknown'\n"); | |
3313 | $p->{license} = 'unknown'; | |
3314 | } | |
3315 | unless (exists $self->valid_licenses->{ $p->{license} }) { | |
3316 | die "Unknown license type '$p->{license}'"; | |
3317 | } | |
3318 | ||
3319 | # If we're in the distdir, the metafile may exist and be non-writable. | |
3320 | $self->delete_filetree($metafile); | |
3321 | $self->log_info("Creating $metafile\n"); | |
3322 | ||
3323 | # Since we're building ourself, we have to do some special stuff | |
3324 | # here: the ConfigData module is found in blib/lib. | |
3325 | local @INC = @INC; | |
3326 | if (($self->module_name || '') eq 'Module::Build') { | |
3327 | $self->depends_on('config_data'); | |
3328 | push @INC, File::Spec->catdir($self->blib, 'lib'); | |
3329 | } | |
3330 | ||
3331 | $self->write_metafile; | |
3332 | } | |
3333 | ||
3334 | sub write_metafile { | |
3335 | my $self = shift; | |
3336 | my $metafile = $self->metafile; | |
3337 | ||
3338 | if ($self->_mb_feature('YAML_support')) { | |
3339 | require YAML; | |
3340 | require YAML::Node; | |
3341 | ||
3342 | # We use YAML::Node to get the order nice in the YAML file. | |
3343 | $self->prepare_metadata( my $node = YAML::Node->new({}) ); | |
3344 | ||
3345 | # YAML API changed after version 0.30 | |
3346 | my $yaml_sub = $YAML::VERSION le '0.30' ? \&YAML::StoreFile : \&YAML::DumpFile; | |
3347 | $self->{wrote_metadata} = $yaml_sub->($metafile, $node ); | |
3348 | ||
3349 | } else { | |
a314697d RS |
3350 | require Module::Build::YAML; |
3351 | my (%node, @order_keys); | |
3352 | $self->prepare_metadata(\%node, \@order_keys); | |
3353 | $node{_order} = \@order_keys; | |
3354 | &Module::Build::YAML::DumpFile($metafile, \%node); | |
3355 | $self->{wrote_metadata} = 1; | |
bb4e9162 YST |
3356 | } |
3357 | ||
3358 | $self->_add_to_manifest('MANIFEST', $metafile); | |
3359 | } | |
3360 | ||
3361 | sub prepare_metadata { | |
a314697d | 3362 | my ($self, $node, $keys) = @_; |
bb4e9162 YST |
3363 | my $p = $self->{properties}; |
3364 | ||
a314697d RS |
3365 | # A little helper sub |
3366 | my $add_node = sub { | |
3367 | my ($name, $val) = @_; | |
3368 | $node->{$name} = $val; | |
3369 | push @$keys, $name if $keys; | |
3370 | }; | |
3371 | ||
bb4e9162 YST |
3372 | foreach (qw(dist_name dist_version dist_author dist_abstract license)) { |
3373 | (my $name = $_) =~ s/^dist_//; | |
a314697d | 3374 | $add_node->($name, $self->$_()); |
47f13fd5 | 3375 | die "ERROR: Missing required field '$_' for META.yml\n" |
bb4e9162 YST |
3376 | unless defined($node->{$name}) && length($node->{$name}); |
3377 | } | |
0ec9ad96 | 3378 | $node->{version} = '' . $node->{version}; # Stringify version objects |
bb4e9162 YST |
3379 | |
3380 | if (defined( $self->license ) && | |
3381 | defined( my $url = $self->valid_licenses->{ $self->license } )) { | |
3382 | $node->{resources}{license} = $url; | |
3383 | } | |
3384 | ||
3385 | foreach ( @{$self->prereq_action_types} ) { | |
a314697d RS |
3386 | if (exists $p->{$_} and keys %{ $p->{$_} }) { |
3387 | $add_node->($_, $p->{$_}); | |
3388 | } | |
bb4e9162 YST |
3389 | } |
3390 | ||
a314697d RS |
3391 | if (exists $p->{dynamic_config}) { |
3392 | $add_node->('dynamic_config', $p->{dynamic_config}); | |
3393 | } | |
bb4e9162 YST |
3394 | my $pkgs = eval { $self->find_dist_packages }; |
3395 | if ($@) { | |
7a501b10 | 3396 | $self->log_warn("$@\nWARNING: Possible missing or corrupt 'MANIFEST' file.\n" . |
bb4e9162 YST |
3397 | "Nothing to enter for 'provides' field in META.yml\n"); |
3398 | } else { | |
3399 | $node->{provides} = $pkgs if %$pkgs; | |
3400 | } | |
3401 | ; | |
a314697d RS |
3402 | if (exists $p->{no_index}) { |
3403 | $add_node->('no_index', $p->{no_index}); | |
3404 | } | |
bb4e9162 | 3405 | |
a314697d | 3406 | $add_node->('generated_by', "Module::Build version $Module::Build::VERSION"); |
bb4e9162 | 3407 | |
a314697d RS |
3408 | $add_node->('meta-spec', |
3409 | {version => '1.2', | |
3410 | url => 'http://module-build.sourceforge.net/META-spec-v1.2.html', | |
3411 | }); | |
bb4e9162 YST |
3412 | |
3413 | while (my($k, $v) = each %{$self->meta_add}) { | |
a314697d | 3414 | $add_node->($k, $v); |
bb4e9162 YST |
3415 | } |
3416 | ||
3417 | while (my($k, $v) = each %{$self->meta_merge}) { | |
3418 | $self->_hash_merge($node, $k, $v); | |
3419 | } | |
3420 | ||
3421 | return $node; | |
3422 | } | |
3423 | ||
3424 | sub _read_manifest { | |
3425 | my ($self, $file) = @_; | |
3426 | return undef unless -e $file; | |
3427 | ||
3428 | require ExtUtils::Manifest; # ExtUtils::Manifest is not warnings clean. | |
3429 | local ($^W, $ExtUtils::Manifest::Quiet) = (0,1); | |
3430 | return scalar ExtUtils::Manifest::maniread($file); | |
3431 | } | |
3432 | ||
3433 | sub find_dist_packages { | |
3434 | my $self = shift; | |
3435 | ||
3436 | # Only packages in .pm files are candidates for inclusion here. | |
3437 | # Only include things in the MANIFEST, not things in developer's | |
3438 | # private stock. | |
3439 | ||
3440 | my $manifest = $self->_read_manifest('MANIFEST') | |
3441 | or die "Can't find dist packages without a MANIFEST file - run 'manifest' action first"; | |
3442 | ||
3443 | # Localize | |
3444 | my %dist_files = map { $self->localize_file_path($_) => $_ } | |
3445 | keys %$manifest; | |
3446 | ||
3447 | my @pm_files = grep {exists $dist_files{$_}} keys %{ $self->find_pm_files }; | |
3448 | ||
3449 | # First, we enumerate all packages & versions, | |
3450 | # seperating into primary & alternative candidates | |
3451 | my( %prime, %alt ); | |
3452 | foreach my $file (@pm_files) { | |
3453 | next if $dist_files{$file} =~ m{^t/}; # Skip things in t/ | |
3454 | ||
3455 | my @path = split( /\//, $dist_files{$file} ); | |
3456 | (my $prime_package = join( '::', @path[1..$#path] )) =~ s/\.pm$//; | |
3457 | ||
3458 | my $pm_info = Module::Build::ModuleInfo->new_from_file( $file ); | |
3459 | ||
3460 | foreach my $package ( $pm_info->packages_inside ) { | |
3461 | next if $package eq 'main'; # main can appear numerous times, ignore | |
3462 | next if grep /^_/, split( /::/, $package ); # private package, ignore | |
3463 | ||
3464 | my $version = $pm_info->version( $package ); | |
3465 | ||
3466 | if ( $package eq $prime_package ) { | |
3467 | if ( exists( $prime{$package} ) ) { | |
3468 | # M::B::ModuleInfo will handle this conflict | |
3469 | die "Unexpected conflict in '$package'; multiple versions found.\n"; | |
3470 | } else { | |
3471 | $prime{$package}{file} = $dist_files{$file}; | |
3472 | $prime{$package}{version} = $version if defined( $version ); | |
3473 | } | |
3474 | } else { | |
3475 | push( @{$alt{$package}}, { | |
3476 | file => $dist_files{$file}, | |
3477 | version => $version, | |
3478 | } ); | |
3479 | } | |
3480 | } | |
3481 | } | |
3482 | ||
3483 | # Then we iterate over all the packages found above, identifying conflicts | |
3484 | # and selecting the "best" candidate for recording the file & version | |
3485 | # for each package. | |
3486 | foreach my $package ( keys( %alt ) ) { | |
3487 | my $result = $self->_resolve_module_versions( $alt{$package} ); | |
3488 | ||
3489 | if ( exists( $prime{$package} ) ) { # primary package selected | |
3490 | ||
3491 | if ( $result->{err} ) { | |
3492 | # Use the selected primary package, but there are conflicting | |
3493 | # errors amoung multiple alternative packages that need to be | |
3494 | # reported | |
3495 | $self->log_warn( | |
3496 | "Found conflicting versions for package '$package'\n" . | |
3497 | " $prime{$package}{file} ($prime{$package}{version})\n" . | |
3498 | $result->{err} | |
3499 | ); | |
3500 | ||
3501 | } elsif ( defined( $result->{version} ) ) { | |
3502 | # There is a primary package selected, and exactly one | |
3503 | # alternative package | |
3504 | ||
3505 | if ( exists( $prime{$package}{version} ) && | |
3506 | defined( $prime{$package}{version} ) ) { | |
3507 | # Unless the version of the primary package agrees with the | |
3508 | # version of the alternative package, report a conflict | |
3509 | if ( $self->compare_versions( $prime{$package}{version}, '!=', | |
3510 | $result->{version} ) ) { | |
3511 | $self->log_warn( | |
3512 | "Found conflicting versions for package '$package'\n" . | |
3513 | " $prime{$package}{file} ($prime{$package}{version})\n" . | |
3514 | " $result->{file} ($result->{version})\n" | |
3515 | ); | |
3516 | } | |
3517 | ||
3518 | } else { | |
3519 | # The prime package selected has no version so, we choose to | |
3520 | # use any alternative package that does have a version | |
3521 | $prime{$package}{file} = $result->{file}; | |
3522 | $prime{$package}{version} = $result->{version}; | |
3523 | } | |
3524 | ||
3525 | } else { | |
3526 | # no alt package found with a version, but we have a prime | |
3527 | # package so we use it whether it has a version or not | |
3528 | } | |
3529 | ||
3530 | } else { # No primary package was selected, use the best alternative | |
3531 | ||
3532 | if ( $result->{err} ) { | |
3533 | $self->log_warn( | |
3534 | "Found conflicting versions for package '$package'\n" . | |
3535 | $result->{err} | |
3536 | ); | |
3537 | } | |
3538 | ||
3539 | # Despite possible conflicting versions, we choose to record | |
3540 | # something rather than nothing | |
3541 | $prime{$package}{file} = $result->{file}; | |
3542 | $prime{$package}{version} = $result->{version} | |
3543 | if defined( $result->{version} ); | |
3544 | } | |
3545 | } | |
3546 | ||
77e96e88 RGS |
3547 | # Stringify versions. Can't use exists() here because of bug in YAML::Node. |
3548 | for (grep defined $_->{version}, values %prime) { | |
3549 | $_->{version} = '' . $_->{version}; | |
7a501b10 SP |
3550 | } |
3551 | ||
bb4e9162 YST |
3552 | return \%prime; |
3553 | } | |
3554 | ||
3555 | # seperate out some of the conflict resolution logic from | |
3556 | # $self->find_dist_packages(), above, into a helper function. | |
3557 | # | |
3558 | sub _resolve_module_versions { | |
3559 | my $self = shift; | |
3560 | ||
3561 | my $packages = shift; | |
3562 | ||
3563 | my( $file, $version ); | |
3564 | my $err = ''; | |
3565 | foreach my $p ( @$packages ) { | |
3566 | if ( defined( $p->{version} ) ) { | |
3567 | if ( defined( $version ) ) { | |
3568 | if ( $self->compare_versions( $version, '!=', $p->{version} ) ) { | |
3569 | $err .= " $p->{file} ($p->{version})\n"; | |
3570 | } else { | |
3571 | # same version declared multiple times, ignore | |
3572 | } | |
3573 | } else { | |
3574 | $file = $p->{file}; | |
3575 | $version = $p->{version}; | |
3576 | } | |
3577 | } | |
3578 | $file ||= $p->{file} if defined( $p->{file} ); | |
3579 | } | |
3580 | ||
3581 | if ( $err ) { | |
3582 | $err = " $file ($version)\n" . $err; | |
3583 | } | |
3584 | ||
3585 | my %result = ( | |
3586 | file => $file, | |
3587 | version => $version, | |
3588 | err => $err | |
3589 | ); | |
3590 | ||
3591 | return \%result; | |
3592 | } | |
3593 | ||
3594 | sub make_tarball { | |
3595 | my ($self, $dir, $file) = @_; | |
3596 | $file ||= $dir; | |
3597 | ||
3598 | $self->log_info("Creating $file.tar.gz\n"); | |
3599 | ||
3600 | if ($self->{args}{tar}) { | |
3601 | my $tar_flags = $self->verbose ? 'cvf' : 'cf'; | |
3602 | $self->do_system($self->split_like_shell($self->{args}{tar}), $tar_flags, "$file.tar", $dir); | |
3603 | $self->do_system($self->split_like_shell($self->{args}{gzip}), "$file.tar") if $self->{args}{gzip}; | |
3604 | } else { | |
3605 | require Archive::Tar; | |
3606 | # Archive::Tar versions >= 1.09 use the following to enable a compatibility | |
3607 | # hack so that the resulting archive is compatible with older clients. | |
3608 | $Archive::Tar::DO_NOT_USE_PREFIX = 0; | |
3609 | my $files = $self->rscan_dir($dir); | |
3610 | Archive::Tar->create_archive("$file.tar.gz", 1, @$files); | |
3611 | } | |
3612 | } | |
3613 | ||
dc8021d3 SP |
3614 | sub install_path { |
3615 | my $self = shift; | |
3616 | my( $type, $value ) = ( @_, '<empty>' ); | |
3617 | ||
3618 | Carp::croak( 'Type argument missing' ) | |
3619 | unless defined( $type ); | |
3620 | ||
3621 | my $map = $self->{properties}{install_path}; | |
3622 | return $map unless @_; | |
3623 | ||
3624 | # delete existing value if $value is literal undef() | |
3625 | unless ( defined( $value ) ) { | |
3626 | delete( $map->{$type} ); | |
3627 | return undef; | |
3628 | } | |
3629 | ||
3630 | # return existing value if no new $value is given | |
3631 | if ( $value eq '<empty>' ) { | |
3632 | return undef unless exists $map->{$type}; | |
3633 | return $map->{$type}; | |
3634 | } | |
3635 | ||
3636 | # set value if $value is a valid relative path | |
3637 | return $map->{$type} = $value; | |
3638 | } | |
3639 | ||
bb4e9162 | 3640 | sub install_base_relpaths { |
dc8021d3 SP |
3641 | # Usage: install_base_relpaths(), install_base_relpaths('lib'), |
3642 | # or install_base_relpaths('lib' => $value); | |
bb4e9162 YST |
3643 | my $self = shift; |
3644 | my $map = $self->{properties}{install_base_relpaths}; | |
3645 | return $map unless @_; | |
dc8021d3 | 3646 | return $self->_relpaths($map, @_); |
bb4e9162 YST |
3647 | } |
3648 | ||
3649 | ||
3650 | # Translated from ExtUtils::MM_Any::init_INSTALL_from_PREFIX | |
3651 | sub prefix_relative { | |
3652 | my ($self, $type) = @_; | |
3653 | my $installdirs = $self->installdirs; | |
3654 | ||
3655 | my $relpath = $self->install_sets($installdirs)->{$type}; | |
3656 | ||
3657 | return $self->_prefixify($relpath, | |
3658 | $self->original_prefix($installdirs), | |
3659 | $type, | |
3660 | ); | |
3661 | } | |
3662 | ||
dc8021d3 SP |
3663 | sub _relpaths { |
3664 | my $self = shift; | |
3665 | my( $map, $type, $value ) = ( @_, '<empty>' ); | |
3666 | ||
3667 | Carp::croak( 'Type argument missing' ) | |
3668 | unless defined( $type ); | |
3669 | ||
3670 | my @value = (); | |
3671 | ||
3672 | # delete existing value if $value is literal undef() | |
3673 | unless ( defined( $value ) ) { | |
3674 | delete( $map->{$type} ); | |
3675 | return undef; | |
3676 | } | |
3677 | ||
3678 | # return existing value if no new $value is given | |
3679 | elsif ( $value eq '<empty>' ) { | |
3680 | return undef unless exists $map->{$type}; | |
3681 | @value = @{ $map->{$type} }; | |
3682 | } | |
3683 | ||
3684 | # set value if $value is a valid relative path | |
3685 | else { | |
3686 | Carp::croak( "Value must be a relative path" ) | |
3687 | if File::Spec::Unix->file_name_is_absolute($value); | |
3688 | ||
3689 | @value = split( /\//, $value ); | |
3690 | $map->{$type} = \@value; | |
3691 | } | |
3692 | ||
3693 | return File::Spec->catdir( @value ); | |
3694 | } | |
bb4e9162 YST |
3695 | |
3696 | # Defaults to use in case the config install paths cannot be prefixified. | |
3697 | sub prefix_relpaths { | |
dc8021d3 SP |
3698 | # Usage: prefix_relpaths('site'), prefix_relpaths('site', 'lib'), |
3699 | # or prefix_relpaths('site', 'lib' => $value); | |
bb4e9162 YST |
3700 | my $self = shift; |
3701 | my $installdirs = shift || $self->installdirs; | |
3702 | my $map = $self->{properties}{prefix_relpaths}{$installdirs}; | |
3703 | return $map unless @_; | |
dc8021d3 | 3704 | return $self->_relpaths($map, @_); |
bb4e9162 YST |
3705 | } |
3706 | ||
3707 | ||
3708 | # Translated from ExtUtils::MM_Unix::prefixify() | |
3709 | sub _prefixify { | |
3710 | my($self, $path, $sprefix, $type) = @_; | |
3711 | ||
3712 | my $rprefix = $self->prefix; | |
3713 | $rprefix .= '/' if $sprefix =~ m|/$|; | |
3714 | ||
3715 | $self->log_verbose(" prefixify $path from $sprefix to $rprefix\n") | |
3716 | if defined( $path ) && length( $path ); | |
3717 | ||
3718 | if( !defined( $path ) || ( length( $path ) == 0 ) ) { | |
3719 | $self->log_verbose(" no path to prefixify, falling back to default.\n"); | |
3720 | return $self->_prefixify_default( $type, $rprefix ); | |
3721 | } elsif( !File::Spec->file_name_is_absolute($path) ) { | |
3722 | $self->log_verbose(" path is relative, not prefixifying.\n"); | |
3723 | } elsif( $sprefix eq $rprefix ) { | |
3724 | $self->log_verbose(" no new prefix.\n"); | |
3725 | } elsif( $path !~ s{^\Q$sprefix\E\b}{}s ) { | |
3726 | $self->log_verbose(" cannot prefixify, falling back to default.\n"); | |
3727 | return $self->_prefixify_default( $type, $rprefix ); | |
3728 | } | |
3729 | ||
3730 | $self->log_verbose(" now $path in $rprefix\n"); | |
3731 | ||
3732 | return $path; | |
3733 | } | |
3734 | ||
3735 | sub _prefixify_default { | |
3736 | my $self = shift; | |
3737 | my $type = shift; | |
3738 | my $rprefix = shift; | |
3739 | ||
3740 | my $default = $self->prefix_relpaths($self->installdirs, $type); | |
3741 | if( !$default ) { | |
3742 | $self->log_verbose(" no default install location for type '$type', using prefix '$rprefix'.\n"); | |
3743 | return $rprefix; | |
3744 | } else { | |
3745 | return $default; | |
3746 | } | |
3747 | } | |
3748 | ||
3749 | sub install_destination { | |
3750 | my ($self, $type) = @_; | |
3751 | ||
3752 | return $self->install_path($type) if $self->install_path($type); | |
3753 | ||
3754 | if ( $self->install_base ) { | |
3755 | my $relpath = $self->install_base_relpaths($type); | |
3756 | return $relpath ? File::Spec->catdir($self->install_base, $relpath) : undef; | |
3757 | } | |
3758 | ||
3759 | if ( $self->prefix ) { | |
3760 | my $relpath = $self->prefix_relative($type); | |
3761 | return $relpath ? File::Spec->catdir($self->prefix, $relpath) : undef; | |
3762 | } | |
3763 | ||
3764 | return $self->install_sets($self->installdirs)->{$type}; | |
3765 | } | |
3766 | ||
3767 | sub install_types { | |
3768 | my $self = shift; | |
dc8021d3 SP |
3769 | |
3770 | my %types; | |
3771 | if ( $self->install_base ) { | |
3772 | %types = %{$self->install_base_relpaths}; | |
3773 | } elsif ( $self->prefix ) { | |
3774 | %types = %{$self->prefix_relpaths}; | |
3775 | } else { | |
3776 | %types = %{$self->install_sets($self->installdirs)}; | |
3777 | } | |
3778 | ||
3779 | %types = (%types, %{$self->install_path}); | |
3780 | ||
bb4e9162 YST |
3781 | return sort keys %types; |
3782 | } | |
3783 | ||
3784 | sub install_map { | |
3785 | my ($self, $blib) = @_; | |
3786 | $blib ||= $self->blib; | |
3787 | ||
3788 | my( %map, @skipping ); | |
3789 | foreach my $type ($self->install_types) { | |
3790 | my $localdir = File::Spec->catdir( $blib, $type ); | |
3791 | next unless -e $localdir; | |
3792 | ||
3793 | if (my $dest = $self->install_destination($type)) { | |
3794 | $map{$localdir} = $dest; | |
3795 | } else { | |
3796 | push( @skipping, $type ); | |
3797 | } | |
3798 | } | |
3799 | ||
3800 | $self->log_warn( | |
3801 | "WARNING: Can't figure out install path for types: @skipping\n" . | |
3802 | "Files will not be installed.\n" | |
3803 | ) if @skipping; | |
47f13fd5 | 3804 | |
bb4e9162 | 3805 | # Write the packlist into the same place as ExtUtils::MakeMaker. |
a314697d | 3806 | if ($self->create_packlist and my $module_name = $self->module_name) { |
47f13fd5 SP |
3807 | my $archdir = $self->install_destination('arch'); |
3808 | my @ext = split /::/, $module_name; | |
a20c6482 | 3809 | $map{write} = File::Spec->catfile($archdir, 'auto', @ext, '.packlist'); |
47f13fd5 SP |
3810 | } |
3811 | ||
bb4e9162 YST |
3812 | # Handle destdir |
3813 | if (length(my $destdir = $self->destdir || '')) { | |
3814 | foreach (keys %map) { | |
3815 | # Need to remove volume from $map{$_} using splitpath, or else | |
3816 | # we'll create something crazy like C:\Foo\Bar\E:\Baz\Quux | |
d1bd4ef0 JM |
3817 | # VMS will always have the file separate than the path. |
3818 | my ($volume, $path, $file) = File::Spec->splitpath( $map{$_}, 1 ); | |
3819 | ||
3820 | # catdir needs a list of directories, or it will create something | |
3821 | # crazy like volume:[Foo.Bar.volume.Baz.Quux] | |
3822 | my @dirs = File::Spec->splitdir($path); | |
3823 | ||
3824 | # First merge the directories | |
3825 | $path = File::Spec->catdir($destdir, @dirs); | |
3826 | ||
3827 | # Then put the file back on if there is one. | |
3828 | if ($file ne '') { | |
3829 | $map{$_} = File::Spec->catfile($path, $file) | |
3830 | } else { | |
3831 | $map{$_} = $path; | |
3832 | } | |
bb4e9162 YST |
3833 | } |
3834 | } | |
3835 | ||
3836 | $map{read} = ''; # To keep ExtUtils::Install quiet | |
3837 | ||
3838 | return \%map; | |
3839 | } | |
3840 | ||
3841 | sub depends_on { | |
3842 | my $self = shift; | |
3843 | foreach my $action (@_) { | |
3844 | $self->_call_action($action); | |
3845 | } | |
3846 | } | |
3847 | ||
3848 | sub rscan_dir { | |
3849 | my ($self, $dir, $pattern) = @_; | |
3850 | my @result; | |
3851 | local $_; # find() can overwrite $_, so protect ourselves | |
3852 | my $subr = !$pattern ? sub {push @result, $File::Find::name} : | |
3853 | !ref($pattern) || (ref $pattern eq 'Regexp') ? sub {push @result, $File::Find::name if /$pattern/} : | |
3854 | ref($pattern) eq 'CODE' ? sub {push @result, $File::Find::name if $pattern->()} : | |
3855 | die "Unknown pattern type"; | |
3856 | ||
3857 | File::Find::find({wanted => $subr, no_chdir => 1}, $dir); | |
3858 | return \@result; | |
3859 | } | |
3860 | ||
3861 | sub delete_filetree { | |
3862 | my $self = shift; | |
3863 | my $deleted = 0; | |
3864 | foreach (@_) { | |
3865 | next unless -e $_; | |
3866 | $self->log_info("Deleting $_\n"); | |
3867 | File::Path::rmtree($_, 0, 0); | |
3868 | die "Couldn't remove '$_': $!\n" if -e $_; | |
3869 | $deleted++; | |
3870 | } | |
3871 | return $deleted; | |
3872 | } | |
3873 | ||
3874 | sub autosplit_file { | |
3875 | my ($self, $file, $to) = @_; | |
3876 | require AutoSplit; | |
3877 | my $dir = File::Spec->catdir($to, 'lib', 'auto'); | |
3878 | AutoSplit::autosplit($file, $dir); | |
3879 | } | |
3880 | ||
3881 | sub _cbuilder { | |
3882 | # Returns a CBuilder object | |
3883 | ||
3884 | my $self = shift; | |
3885 | my $p = $self->{properties}; | |
3886 | return $p->{_cbuilder} if $p->{_cbuilder}; | |
3887 | return unless $self->_mb_feature('C_support'); | |
3888 | ||
3889 | require ExtUtils::CBuilder; | |
3890 | return $p->{_cbuilder} = ExtUtils::CBuilder->new(config => $self->config); | |
3891 | } | |
3892 | ||
3893 | sub have_c_compiler { | |
3894 | my ($self) = @_; | |
3895 | ||
3896 | my $p = $self->{properties}; | |
3897 | return $p->{have_compiler} if defined $p->{have_compiler}; | |
3898 | ||
3899 | $self->log_verbose("Checking if compiler tools configured... "); | |
3900 | my $b = $self->_cbuilder; | |
3901 | my $have = $b && $b->have_compiler; | |
3902 | $self->log_verbose($have ? "ok.\n" : "failed.\n"); | |
3903 | return $p->{have_compiler} = $have; | |
3904 | } | |
3905 | ||
3906 | sub compile_c { | |
3907 | my ($self, $file, %args) = @_; | |
3908 | my $b = $self->_cbuilder | |
3909 | or die "Module::Build is not configured with C_support"; | |
3910 | ||
3911 | my $obj_file = $b->object_file($file); | |
3912 | $self->add_to_cleanup($obj_file); | |
3913 | return $obj_file if $self->up_to_date($file, $obj_file); | |
3914 | ||
3915 | $b->compile(source => $file, | |
3916 | defines => $args{defines}, | |
3917 | object_file => $obj_file, | |
3918 | include_dirs => $self->include_dirs, | |
3919 | extra_compiler_flags => $self->extra_compiler_flags, | |
3920 | ); | |
3921 | ||
3922 | return $obj_file; | |
3923 | } | |
3924 | ||
3925 | sub link_c { | |
3926 | my ($self, $to, $file_base) = @_; | |
3927 | my $p = $self->{properties}; # For convenience | |
3928 | ||
3929 | my $spec = $self->_infer_xs_spec($file_base); | |
3930 | ||
3931 | $self->add_to_cleanup($spec->{lib_file}); | |
3932 | ||
3933 | my $objects = $p->{objects} || []; | |
3934 | ||
3935 | return $spec->{lib_file} | |
3936 | if $self->up_to_date([$spec->{obj_file}, @$objects], | |
3937 | $spec->{lib_file}); | |
3938 | ||
3939 | my $module_name = $self->module_name; | |
3940 | $module_name ||= $spec->{module_name}; | |
3941 | ||
3942 | my $b = $self->_cbuilder | |
3943 | or die "Module::Build is not configured with C_support"; | |
3944 | $b->link( | |
3945 | module_name => $module_name, | |
3946 | objects => [$spec->{obj_file}, @$objects], | |
3947 | lib_file => $spec->{lib_file}, | |
3948 | extra_linker_flags => $p->{extra_linker_flags} ); | |
3949 | ||
3950 | return $spec->{lib_file}; | |
3951 | } | |
3952 | ||
3953 | sub compile_xs { | |
3954 | my ($self, $file, %args) = @_; | |
3955 | ||
3956 | $self->log_info("$file -> $args{outfile}\n"); | |
3957 | ||
3958 | if (eval {require ExtUtils::ParseXS; 1}) { | |
3959 | ||
3960 | ExtUtils::ParseXS::process_file( | |
3961 | filename => $file, | |
3962 | prototypes => 0, | |
3963 | output => $args{outfile}, | |
3964 | ); | |
3965 | } else { | |
3966 | # Ok, I give up. Just use backticks. | |
3967 | ||
3968 | my $xsubpp = Module::Build::ModuleInfo->find_module_by_name('ExtUtils::xsubpp') | |
3969 | or die "Can't find ExtUtils::xsubpp in INC (@INC)"; | |
3970 | ||
3971 | my @typemaps; | |
3972 | push @typemaps, Module::Build::ModuleInfo->find_module_by_name('ExtUtils::typemap', \@INC); | |
3973 | my $lib_typemap = Module::Build::ModuleInfo->find_module_by_name('typemap', ['lib']); | |
3974 | if (defined $lib_typemap and -e $lib_typemap) { | |
3975 | push @typemaps, 'typemap'; | |
3976 | } | |
a314697d | 3977 | @typemaps = map {+'-typemap', $_} @typemaps; |
bb4e9162 | 3978 | |
77e96e88 | 3979 | my $cf = $self->{config}; |
bb4e9162 YST |
3980 | my $perl = $self->{properties}{perl}; |
3981 | ||
77e96e88 | 3982 | my @command = ($perl, "-I".$cf->get('installarchlib'), "-I".$cf->get('installprivlib'), $xsubpp, '-noprototypes', |
a314697d | 3983 | @typemaps, $file); |
bb4e9162 | 3984 | |
a314697d | 3985 | $self->log_info("@command\n"); |
bb4e9162 | 3986 | my $fh = IO::File->new("> $args{outfile}") or die "Couldn't write $args{outfile}: $!"; |
a314697d | 3987 | print {$fh} $self->_backticks(@command); |
bb4e9162 YST |
3988 | close $fh; |
3989 | } | |
3990 | } | |
3991 | ||
3992 | sub split_like_shell { | |
3993 | my ($self, $string) = @_; | |
3994 | ||
3995 | return () unless defined($string); | |
3996 | return @$string if UNIVERSAL::isa($string, 'ARRAY'); | |
3997 | $string =~ s/^\s+|\s+$//g; | |
3998 | return () unless length($string); | |
3999 | ||
4000 | return Text::ParseWords::shellwords($string); | |
4001 | } | |
4002 | ||
4003 | sub run_perl_script { | |
4004 | my ($self, $script, $preargs, $postargs) = @_; | |
4005 | foreach ($preargs, $postargs) { | |
4006 | $_ = [ $self->split_like_shell($_) ] unless ref(); | |
4007 | } | |
4008 | return $self->run_perl_command([@$preargs, $script, @$postargs]); | |
4009 | } | |
4010 | ||
4011 | sub run_perl_command { | |
4012 | # XXX Maybe we should accept @args instead of $args? Must resolve | |
4013 | # this before documenting. | |
4014 | my ($self, $args) = @_; | |
4015 | $args = [ $self->split_like_shell($args) ] unless ref($args); | |
4016 | my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter; | |
4017 | ||
4018 | # Make sure our local additions to @INC are propagated to the subprocess | |
77e96e88 | 4019 | local $ENV{PERL5LIB} = join $self->config('path_sep'), $self->_added_to_INC; |
bb4e9162 YST |
4020 | |
4021 | return $self->do_system($perl, @$args); | |
4022 | } | |
4023 | ||
4024 | # Infer various data from the path of the input filename | |
4025 | # that is needed to create output files. | |
4026 | # The input filename is expected to be of the form: | |
4027 | # lib/Module/Name.ext or Module/Name.ext | |
4028 | sub _infer_xs_spec { | |
4029 | my $self = shift; | |
4030 | my $file = shift; | |
4031 | ||
4032 | my $cf = $self->{config}; | |
4033 | ||
4034 | my %spec; | |
4035 | ||
4036 | my( $v, $d, $f ) = File::Spec->splitpath( $file ); | |
4037 | my @d = File::Spec->splitdir( $d ); | |
4038 | (my $file_base = $f) =~ s/\.[^.] |