MANIFEST is created dynamically, we leave MANIFEST.SKIP alone (dist-specific)
[bioperl-live.git] / Bio / Root / Build.pm
blob33085368a9a2569d05ffcc759e25aee03e13b5c0
2 # BioPerl module for Bio::Root::Build
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Sendu Bala <bix@sendu.me.uk>
8 # Copyright Sendu Bala
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
14 =head1 NAME
16 Bio::Root::Build - A common Module::Build subclass base for BioPerl distributions
18 =head1 SYNOPSIS
20 ...TO BE ADDED
22 =head1 DESCRIPTION
24 This is a subclass of Module::Build so we can override certain methods and do
25 fancy stuff
27 It was first written against Module::Build::Base v0.2805. Many of the methods
28 here are copy/pasted from there in their entirety just to change one or two
29 minor things, since for the most part Module::Build::Base code is hard to
30 cleanly override.
32 B<Note>: per bug 3196, the majority of the code in this module has been revised
33 or commented out to bring it in line with the Module::Build API. In particular,
34 'requires/recommends' tags in the Build.PL file were not of the same format as
35 those for Module::Build, and so caused serious issues with newer versions
36 (including giving incorrect meta data). Other problematic methods involving
37 automatic installation of prereq modules via CPAN were also removed as they do
38 not work with more modern perl tools such as perlbrew and cpanm.
40 =head1 FEEDBACK
42 =head2 Mailing Lists
44 User feedback is an integral part of the evolution of this and other
45 Bioperl modules. Send your comments and suggestions preferably to
46 the Bioperl mailing list. Your participation is much appreciated.
48 bioperl-l@bioperl.org - General discussion
49 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
51 =head2 Support
53 Please direct usage questions or support issues to the mailing list:
55 I<bioperl-l@bioperl.org>
57 rather than to the module maintainer directly. Many experienced and
58 reponsive experts will be able look at the problem and quickly
59 address it. Please include a thorough description of the problem
60 with code and data examples if at all possible.
62 =head2 Reporting Bugs
64 Report bugs to the Bioperl bug tracking system to help us keep track
65 of the bugs and their resolution. Bug reports can be submitted via
66 the web:
68 https://redmine.open-bio.org/projects/bioperl/
70 =head1 AUTHOR - Sendu Bala
72 Email bix@sendu.me.uk
74 =head1 APPENDIX
76 The rest of the documentation details each of the object methods.
77 Internal methods are usually preceded with a _
79 =cut
81 package Bio::Root::Build;
83 BEGIN {
84 # we really need Module::Build to be installed
85 eval "use base Module::Build; 1" or die "This package requires Module::Build v0.2805 or greater to install itself.\n$@";
87 # ensure we'll be able to reload this module later by adding its path to inc
88 use Cwd;
89 use lib Cwd::cwd();
92 use strict;
93 use warnings;
95 our $VERSION = '1.006900'; # pre-1.7
96 our @extra_types = qw(options excludes_os feature_requires test); # test must always be last in the list!
97 our $checking_types = "requires|conflicts|".join("|", @extra_types);
99 # our modules are in Bio, not lib
100 sub find_pm_files {
101 my $self = shift;
102 foreach my $pm (@{$self->rscan_dir('Bio', qr/\.pm$/)}) {
103 $self->{properties}{pm_files}->{$pm} = File::Spec->catfile('lib', $pm);
106 $self->_find_file_by_type('pm', 'lib');
109 # ask what scripts to install (this method is unique to bioperl)
110 sub choose_scripts {
111 my $self = shift;
112 my $accept = shift;
114 # we can offer interactive installation by groups only if we have subdirs
115 # in scripts and no .PLS files there
116 opendir(my $scripts_dir, 'scripts') or die "Can't open directory 'scripts': $!\n";
117 my $int_ok = 0;
118 my @group_dirs;
120 # only retain top-level script directories (the 'categories')
121 while (my $thing = readdir($scripts_dir)) {
122 next if $thing =~ /^\./;
123 $thing = File::Spec->catfile('scripts', $thing);
124 if (-d $thing) {
125 $int_ok = 1;
126 push(@group_dirs, $thing);
129 closedir($scripts_dir);
130 my $question = $int_ok ? "Install [a]ll BioPerl scripts, [n]one, ".
131 "or choose groups [i]nteractively?" : "Install [a]ll BioPerl scripts ".
132 "or [n]one?";
134 my $prompt = $accept ? 'a' : $self->prompt($question, 'a');
136 if ($prompt =~ /^[aA]/) {
137 $self->log_info(" - will install all scripts\n");
138 $self->notes(chosen_scripts => 'all');
140 elsif ($prompt =~ /^[iI]/) {
141 $self->log_info(" - will install interactively:\n");
143 my @chosen_scripts;
144 foreach my $group_dir (@group_dirs) {
145 my $group = File::Basename::basename($group_dir);
146 print " * group '$group' has:\n";
148 my @script_files = @{$self->rscan_dir($group_dir, qr/\.PLS$|\.pl$/)};
149 foreach my $script_file (@script_files) {
150 my $script = File::Basename::basename($script_file);
151 print " $script\n";
154 my $result = $self->prompt(" Install scripts for group '$group'? [y]es [n]o [q]uit", 'n');
155 die if $result =~ /^[qQ]/;
156 if ($result =~ /^[yY]/) {
157 $self->log_info(" + will install group '$group'\n");
158 push(@chosen_scripts, @script_files);
160 else {
161 $self->log_info(" - will not install group '$group'\n");
165 my $chosen_scripts = @chosen_scripts ? join("|", @chosen_scripts) : 'none';
167 $self->notes(chosen_scripts => $chosen_scripts);
169 else {
170 $self->log_info(" - won't install any scripts\n");
171 $self->notes(chosen_scripts => 'none');
174 print "\n";
177 # our version of script_files doesn't take args but just installs those scripts
178 # requested by the user after choose_scripts() is called. If it wasn't called,
179 # installs all scripts in scripts directory
180 sub script_files {
181 my $self = shift;
183 unless (-d 'scripts') {
184 return {};
187 my $chosen_scripts = $self->notes('chosen_scripts');
188 if ($chosen_scripts) {
189 return if $chosen_scripts eq 'none';
190 return { map {$_, 1} split(/\|/, $chosen_scripts) } unless $chosen_scripts eq 'all';
193 return $_ = { map {$_,1} @{$self->rscan_dir('scripts', qr/\.PLS$|\.pl$/)} };
196 # process scripts normally, except that we change name from *.PLS to bp_*.pl
197 sub process_script_files {
198 my $self = shift;
199 my $files = $self->find_script_files;
200 return unless keys %$files;
202 my $script_dir = File::Spec->catdir($self->blib, 'script');
203 File::Path::mkpath( $script_dir );
205 foreach my $file (keys %$files) {
206 my $result = $self->copy_if_modified($file, $script_dir, 'flatten') or next;
207 $self->fix_shebang_line($result) unless $self->os_type eq 'VMS';
208 $self->make_executable($result);
210 my $final = File::Basename::basename($result);
211 $final =~ s/\.PLS$/\.pl/; # change from .PLS to .pl
212 $final =~ s/^/bp_/ unless $final =~ /^bp/; # add the "bp" prefix
213 $final = File::Spec->catfile($script_dir, $final);
214 # silence scripts
215 #$self->log_info("$result -> $final\n");
216 if (-e $final) {
217 unlink $final || warn "[WARNING] Deleting '$final' failed!\n";
219 File::Copy::move($result, $final) or die "Can't rename '$result' to '$final': $!";
223 # extended to handle extra checking types
224 #sub features {
225 # my $self = shift;
226 # my $ph = $self->{phash};
228 # if (@_) {
229 # my $key = shift;
230 # if ($ph->{features}->exists($key)) {
231 # return $ph->{features}->access($key, @_);
234 # if (my $info = $ph->{auto_features}->access($key)) {
235 # my $failures = $self->prereq_failures($info);
236 # my $disabled = grep( /^(?:\w+_)?(?:$checking_types)$/, keys %$failures ) ? 1 : 0;
237 # return !$disabled;
240 # return $ph->{features}->access($key, @_);
243 # # No args - get the auto_features & overlay the regular features
244 # my %features;
245 # my %auto_features = $ph->{auto_features}->access();
246 # while (my ($name, $info) = each %auto_features) {
247 # my $failures = $self->prereq_failures($info);
248 # my $disabled = grep( /^(?:\w+_)?(?:$checking_types)$/, keys %$failures ) ? 1 : 0;
249 # $features{$name} = $disabled ? 0 : 1;
251 # %features = (%features, $ph->{features}->access());
253 # return wantarray ? %features : \%features;
255 #*feature = \&features;
257 # overridden to fix a stupid bug in Module::Build and extended to handle extra
258 # checking types
259 #sub check_autofeatures {
260 # my ($self) = @_;
261 # my $features = $self->auto_features;
263 # return unless %$features;
265 # $self->log_info("Checking features:\n");
267 # my $max_name_len = 0; # this wasn't set to 0 in Module::Build, causing warning in next line
268 # $max_name_len = ( length($_) > $max_name_len ) ? length($_) : $max_name_len for keys %$features;
270 # while (my ($name, $info) = each %$features) {
271 # $self->log_info(" $name" . '.' x ($max_name_len - length($name) + 4));
272 # if ($name eq 'PL_files') {
273 # print "got $name => $info\n";
274 # print "info has:\n";
275 # while (my ($key, $val) = each %$info) {
276 # print " $key => $val\n";
280 # if ( my $failures = $self->prereq_failures($info) ) {
281 # my $disabled = grep( /^(?:\w+_)?(?:$checking_types)$/, keys %$failures ) ? 1 : 0;
282 # $self->log_info( $disabled ? "disabled\n" : "enabled\n" );
284 # my $log_text;
285 # while (my ($type, $prereqs) = each %$failures) {
286 # while (my ($module, $status) = each %$prereqs) {
287 # my $required = ($type =~ /^(?:\w+_)?(?:requires|conflicts)$/) ? 1 : 0;
288 # my $prefix = ($required) ? '-' : '*';
289 # $log_text .= " $prefix $status->{message}\n";
292 # $self->log_warn($log_text) if $log_text && ! $self->quiet;
294 # else {
295 # $self->log_info("enabled\n");
299 # $self->log_info("\n");
302 # TODO: STDERR output redirect is causing some installations to fail, commenting
303 # out until a fix is in place
305 # overriden just to hide pointless ugly warnings
306 #sub check_installed_status {
307 # my $self = shift;
309 # open (my $olderr, ">&". fileno(STDERR));
310 # open(STDERR, "/dev/null");
311 # my $return = $self->SUPER::check_installed_status(@_);
312 # open(STDERR, ">&". fileno($olderr));
313 # return $return;
316 # extend to handle option checking (which takes an array ref) and code test
317 # checking (which takes a code ref and must return a message only on failure)
318 # and excludes_os (which takes an array ref of regexps).
319 # also handles more informative output of recommends section
321 #sub prereq_failures {
322 # my ($self, $info) = @_;
324 # my @types = (@{ $self->prereq_action_types }, @extra_types);
325 # $info ||= {map {$_, $self->$_()} @types};
327 # my $out = {};
328 # foreach my $type (@types) {
329 # my $prereqs = $info->{$type} || next;
331 # my $status = {};
332 # if ($type eq 'test') {
333 # unless (keys %$out) {
334 # if (ref($prereqs) eq 'CODE') {
335 # $status->{message} = &{$prereqs};
337 # # drop the code-ref to avoid Module::Build trying to store
338 # # it with Data::Dumper, generating warnings. (And also, may
339 # # be expensive to run the sub multiple times.)
340 # $info->{$type} = $status->{message};
342 # else {
343 # $status->{message} = $prereqs;
345 # $out->{$type}{'test'} = $status if $status->{message};
348 # elsif ($type eq 'options') {
349 # my @not_ok;
350 # foreach my $wanted_option (@{$prereqs}) {
351 # unless ($self->args($wanted_option)) {
352 # push(@not_ok, $wanted_option);
356 # if (@not_ok > 0) {
357 # $status->{message} = "Command line option(s) '@not_ok' not supplied";
358 # $out->{$type}{'options'} = $status;
361 # elsif ($type eq 'excludes_os') {
362 # foreach my $os (@{$prereqs}) {
363 # if ($^O =~ /$os/i) {
364 # $status->{message} = "This feature isn't supported under your OS ($os)";
365 # $out->{$type}{'excludes_os'} = $status;
366 # last;
370 # else {
371 # while ( my ($modname, $spec) = each %$prereqs ) {
372 # $status = $self->check_installed_status($modname, $spec);
373 # next if $status->{ok};
375 # if ($type =~ /^(?:\w+_)?conflicts$/) {
376 # $status->{conflicts} = delete $status->{need};
377 # $status->{message} = "$modname ($status->{have}) conflicts with this distribution";
379 # elsif ($type =~ /^(?:\w+_)?recommends$/) {
380 # my ($preferred_version, $why, $by_what) = split("/", $spec);
381 # $by_what = join(", ", split(",", $by_what));
382 # $by_what =~ s/, (\S+)$/ and $1/;
384 # $status->{message} = (!ref($status->{have}) && $status->{have} eq '<none>'
385 # ? "Optional prerequisite $modname is not installed"
386 # : "$modname ($status->{have}) is installed, but we prefer to have $preferred_version");
388 # $status->{message} .= "\n (wanted for $why, used by $by_what)";
390 # if ($by_what =~ /\[circular dependency!\]/) {
391 # $preferred_version = -1;
394 # #my $installed = $self->install_optional($modname, $preferred_version, $status->{message});
395 # #next if $installed eq 'ok';
396 # #$status->{message} = $installed unless $installed eq 'skip';
398 # elsif ($type =~ /^feature_requires/) {
399 # # if there is a test code-ref, drop it to avoid
400 # # Module::Build trying to store it with Data::Dumper,
401 # # generating warnings.
402 # delete $info->{test};
404 # else {
405 # my $installed = $self->install_required($modname, $spec, $status->{message});
406 # next if $installed eq 'ok';
407 # $status->{message} = $installed;
410 # $out->{$type}{$modname} = $status;
415 # return keys %{$out} ? $out : return;
418 # install an external module using CPAN prior to testing and installation
419 # should only be called by install_required or install_optional
420 #sub install_prereq {
421 # my ($self, $desired, $version, $required) = @_;
423 # if ($self->under_cpan) {
424 # # Just add to the required hash, which CPAN >= 1.81 will check prior
425 # # to install
426 # $self->{properties}{requires}->{$desired} = $version;
427 # $self->log_info(" I'll get CPAN to prepend the installation of this\n");
428 # return 'ok';
430 # else {
431 # my $question = $required ? "$desired is absolutely required prior to installation: shall I install it now using a CPAN shell?" :
432 # "To install $desired I'll need to open a CPAN shell right now; is that OK?";
433 # my $do_install = $self->y_n($question.' y/n', 'y');
435 # if ($do_install) {
436 # # Here we use CPAN to actually install the desired module, the benefit
437 # # being we continue even if installation fails, and that this works
438 # # even when not using CPAN to install.
439 # require Cwd;
440 # require CPAN;
442 # # Save this because CPAN will chdir all over the place.
443 # my $cwd = Cwd::cwd();
445 # CPAN::Shell->install($desired);
446 # my $msg;
447 # my $expanded = CPAN::Shell->expand("Module", $desired);
448 # if ($expanded && $expanded->uptodate) {
449 # $self->log_info("\n\n*** (back in BioPerl Build.PL) ***\n * You chose to install $desired and it installed fine\n");
450 # $msg = 'ok';
452 # else {
453 # $self->log_info("\n\n*** (back in BioPerl Build.PL) ***\n");
454 # $msg = "You chose to install $desired but it failed to install";
457 # chdir $cwd or die "Cannot chdir() back to $cwd: $!";
458 # return $msg;
460 # else {
461 # return $required ? "You chose not to install the REQUIRED module $desired: you'd better install it yourself manually!" :
462 # "Even though you wanted the optional module $desired, you chose not to actually install it: do it yourself manually.";
467 # install required modules listed in 'requires' or 'build_requires' arg to
468 # new that weren't already installed. Should only be called by prereq_failures
469 #sub install_required {
470 # my ($self, $desired, $version, $msg) = @_;
472 # $self->log_info(" - ERROR: $msg\n");
474 # return $self->install_prereq($desired, $version, 1);
477 # install optional modules listed in 'recommends' arg to new that weren't
478 # already installed. Should only be called by prereq_failures
479 #sub install_optional {
480 # my ($self, $desired, $version, $msg) = @_;
482 # unless (defined $self->{ask_optional}) {
483 # $self->{ask_optional} = $self->args->{accept}
484 # ? 'n' : $self->prompt("Install [a]ll optional external modules, [n]one, or choose [i]nteractively?", 'n');
486 # return 'skip' if $self->{ask_optional} =~ /^n/i;
488 # my $install;
489 # if ($self->{ask_optional} =~ /^a/i) {
490 # $self->log_info(" * $msg\n");
491 # $install = 1;
493 # else {
494 # $install = $self->y_n(" * $msg\n Do you want to install it? y/n", 'n');
497 # my $orig_version = $version;
498 # $version = 0 if $version == -1;
499 # if ($install && ! ($self->{ask_optional} =~ /^a/i && $orig_version == -1)) {
500 # return $self->install_prereq($desired, $version);
502 # else {
503 # my $circular = ($self->{ask_optional} =~ /^a/i && $orig_version == -1) ? " - this is a circular dependency so doesn't get installed when installing 'all' modules. If you really want it, choose modules interactively." : '';
504 # $self->log_info(" * You chose not to install $desired$circular\n");
505 # return 'ok';
509 # there's no official way to discover if being run by CPAN, we take an approach
510 # similar to that of Module::AutoInstall
511 #sub under_cpan {
512 # my $self = shift;
514 # unless (defined $self->{under_cpan}) {
515 # ## modified from Module::AutoInstall
517 # my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING};
518 # if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) {
519 # $self->{under_cpan} = $cpan_env ? 'CPAN' : 'CPANPLUS';
522 # require CPAN;
524 # unless (defined $self->{under_cpan}) {
525 # if ($CPAN::VERSION > '1.89') {
526 # if ($cpan_env) {
527 # $self->{under_cpan} = 'CPAN';
529 # else {
530 # $self->{under_cpan} = 0;
535 # unless (defined $self->{under_cpan}) {
536 # # load cpan config
537 # if ($CPAN::HandleConfig::VERSION) {
538 # # Newer versions of CPAN have a HandleConfig module
539 # CPAN::HandleConfig->load;
541 # else {
542 # # Older versions had the load method in Config directly
543 # CPAN::Config->load;
546 # # Find the CPAN lock-file
547 # my $lock = File::Spec->catfile($CPAN::Config->{cpan_home}, '.lock');
548 # if (-f $lock) {
549 # # Module::AutoInstall now goes on to open the lock file and compare
550 # # its pid to ours, but we're not in a situation where we expect
551 # # the pids to match, so we take the windows approach for all OSes:
552 # # find out if we're in cpan_home
553 # my $cwd = File::Spec->canonpath(Cwd::cwd());
554 # my $cpan = File::Spec->canonpath($CPAN::Config->{cpan_home});
556 # $self->{under_cpan} = index($cwd, $cpan) > -1;
560 # if ($self->{under_cpan}) {
561 # $self->log_info("(I think I'm being run by CPAN/CPANPLUS, so will rely on it to handle prerequisite installation)\n");
563 # else {
564 # $self->log_info("(I think you ran Build.PL directly, so will use CPAN to install prerequisites on demand)\n");
565 # $self->{under_cpan} = 0;
569 # return $self->{under_cpan};
572 # overridden simply to not print the default answer if chosen by hitting return
573 sub prompt {
574 my $self = shift;
575 my $mess = shift or die "prompt() called without a prompt message";
577 my $def;
578 if ( $self->_is_unattended && !@_ ) {
579 die <<EOF;
580 ERROR: This build seems to be unattended, but there is no default value
581 for this question. Aborting.
584 $def = shift if @_;
585 ($def, my $dispdef) = defined $def ? ($def, "[$def] ") : ('', ' ');
587 local $|=1;
588 print "$mess $dispdef";
590 my $ans = $self->_readline();
592 if ( !defined($ans) # Ctrl-D or unattended
593 or !length($ans) ) { # User hit return
594 #print "$def\n"; didn't like this!
595 $ans = $def;
598 return $ans;
601 # like the Module::Build version, except that we always get version from
602 # dist_version
603 #sub find_dist_packages {
604 # my $self = shift;
606 # # Only packages in .pm files are candidates for inclusion here.
607 # # Only include things in the MANIFEST, not things in developer's
608 # # private stock.
610 # my $manifest = $self->_read_manifest('MANIFEST') or die "Can't find dist packages without a MANIFEST file - run 'manifest' action first";
612 # # Localize
613 # my %dist_files = map { $self->localize_file_path($_) => $_ } keys %$manifest;
615 # my @pm_files = grep {exists $dist_files{$_}} keys %{ $self->find_pm_files };
617 # my $actual_version = $self->dist_version;
619 # # First, we enumerate all packages & versions,
620 # # seperating into primary & alternative candidates
621 # my( %prime, %alt );
622 # foreach my $file (@pm_files) {
623 # next if $dist_files{$file} =~ m{^t/}; # Skip things in t/
625 # my @path = split( /\//, $dist_files{$file} );
626 # (my $prime_package = join( '::', @path[1..$#path] )) =~ s/\.pm$//;
628 # my $pm_info = Module::Build::ModuleInfo->new_from_file( $file );
630 # foreach my $package ( $pm_info->packages_inside ) {
631 # next if $package eq 'main'; # main can appear numerous times, ignore
632 # next if grep /^_/, split( /::/, $package ); # private package, ignore
634 # my $version = $pm_info->version( $package );
635 # if ($version && $version != $actual_version) {
636 # $self->log_warn("Package $package had version $version!\n");
638 # $version = $actual_version;
640 # if ( $package eq $prime_package ) {
641 # if ( exists( $prime{$package} ) ) {
642 # # M::B::ModuleInfo will handle this conflict
643 # die "Unexpected conflict in '$package'; multiple versions found.\n";
645 # else {
646 # $prime{$package}{file} = $dist_files{$file};
647 # $prime{$package}{version} = $version if defined( $version );
650 # else {
651 # push( @{$alt{$package}}, { file => $dist_files{$file}, version => $version } );
656 # # Then we iterate over all the packages found above, identifying conflicts
657 # # and selecting the "best" candidate for recording the file & version
658 # # for each package.
659 # foreach my $package ( keys( %alt ) ) {
660 # my $result = $self->_resolve_module_versions( $alt{$package} );
662 # if ( exists( $prime{$package} ) ) { # primary package selected
663 # if ( $result->{err} ) {
664 # # Use the selected primary package, but there are conflicting
665 # # errors amoung multiple alternative packages that need to be
666 # # reported
667 # $self->log_warn("Found conflicting versions for package '$package'\n" .
668 # " $prime{$package}{file} ($prime{$package}{version})\n" . $result->{err});
670 # elsif ( defined( $result->{version} ) ) {
671 # # There is a primary package selected, and exactly one
672 # # alternative package
674 # if ( exists( $prime{$package}{version} ) && defined( $prime{$package}{version} ) ) {
675 # # Unless the version of the primary package agrees with the
676 # # version of the alternative package, report a conflict
677 # if ( $self->compare_versions( $prime{$package}{version}, '!=', $result->{version} ) ) {
678 # $self->log_warn("Found conflicting versions for package '$package'\n" .
679 # " $prime{$package}{file} ($prime{$package}{version})\n" .
680 # " $result->{file} ($result->{version})\n");
683 # else {
684 # # The prime package selected has no version so, we choose to
685 # # use any alternative package that does have a version
686 # $prime{$package}{file} = $result->{file};
687 # $prime{$package}{version} = $result->{version};
690 # else {
691 # # no alt package found with a version, but we have a prime
692 # # package so we use it whether it has a version or not
695 # else { # No primary package was selected, use the best alternative
696 # if ( $result->{err} ) {
697 # $self->log_warn("Found conflicting versions for package '$package'\n" . $result->{err});
700 # # Despite possible conflicting versions, we choose to record
701 # # something rather than nothing
702 # $prime{$package}{file} = $result->{file};
703 # $prime{$package}{version} = $result->{version} if defined( $result->{version} );
707 # # Stringify versions
708 # for (grep exists $_->{version}, values %prime) {
709 # $_->{version} = $_->{version}->stringify if ref($_->{version});
712 # return \%prime;
715 # our recommends syntax contains extra info that needs to be ignored at this
716 # stage
717 #sub _parse_conditions {
718 # my ($self, $spec) = @_;
720 # ($spec) = split("/", $spec);
722 # if ($spec =~ /^\s*([\w.]+)\s*$/) { # A plain number, maybe with dots, letters, and underscores
723 # return (">= $spec");
725 # else {
726 # return split /\s*,\s*/, $spec;
730 # when generating META.yml, we output optional_features syntax (instead of
731 # recommends syntax). Note that as of CPAN v1.9402 nothing useful is done
732 # with this information, which is why we implement our own request to install
733 # the optional modules in install_optional().
734 # Also note that CPAN PLUS complains with an [ERROR] when it sees this META.yml,
735 # but it isn't fatal and installation continues fine.
737 # 'recommends' groups broken up now into separate modules and grouping the
738 # 'requires' instead of lumping modules together (quotes were choking YAML
739 # parsing). Now passes Parse::CPAN::Meta w/o errors.
740 # -cjfields 9-17-09
742 # let us store extra things persistently in _build
743 #sub _construct {
744 # my $self = shift;
746 # # calling SUPER::_construct will dump some of the input to this sub out
747 # # with Data::Dumper, which will complain about code refs. So we replace
748 # # any code refs with dummies first, then put them back afterwards
749 # my %in_hash = @_;
750 # my $auto_features = $in_hash{auto_features} if defined $in_hash{auto_features};
751 # my %code_refs;
752 # if ($auto_features) {
753 # while (my ($key, $hash) = each %{$auto_features}) {
754 # while (my ($sub_key, $val) = each %{$hash}) {
755 # if (ref($val) && ref($val) eq 'CODE') {
756 # $hash->{$sub_key} = 'CODE_ref';
757 # $code_refs{$key}->{$sub_key} = $val;
763 # $self = $self->SUPER::_construct(@_);
765 # my ($p, $ph) = ($self->{properties}, $self->{phash});
767 # if (keys %code_refs) {
768 # while (my ($key, $hash) = each %{$auto_features}) {
769 # if (defined $code_refs{$key}) {
770 # while (my ($sub_key, $code_ref) = each %{$code_refs{$key}}) {
771 # $hash->{$sub_key} = $code_ref;
773 # $ph->{auto_features}->{$key} = $hash;
778 # foreach (qw(manifest_skip post_install_scripts)) {
779 # my $file = File::Spec->catfile($self->config_dir, $_);
780 # $ph->{$_} = Module::Build::Notes->new(file => $file);
781 # $ph->{$_}->restore if -e $file;
784 # return $self;
787 #sub write_config {
788 # my $self = shift;
789 # $self->SUPER::write_config;
791 # # write extra things
792 # $self->{phash}{$_}->write() foreach qw(manifest_skip post_install_scripts);
794 # # be even more certain we can reload ourselves during a resume by copying
795 # # ourselves to _build\lib
796 # # this is only possible for the core distribution where we are actually
797 # # present in the distribution
798 # my $self_filename = File::Spec->catfile('Bio', 'Root', 'Build.pm');
799 # -e $self_filename || return;
801 # my $filename = File::Spec->catfile($self->{properties}{config_dir}, 'lib', 'Bio', 'Root', 'Build.pm');
802 # my $filedir = File::Basename::dirname($filename);
804 # File::Path::mkpath($filedir);
805 # warn "Can't create directory $filedir: $!" unless -d $filedir;
807 # File::Copy::copy($self_filename, $filename);
808 # warn "Unable to copy 'Bio/Root/Build.pm' to '$filename'\n" unless -e $filename;
811 # add a file to the default MANIFEST.SKIP
812 #sub add_to_manifest_skip {
813 # my $self = shift;
814 # my %files = map {$self->localize_file_path($_), 1} @_;
815 # $self->{phash}{manifest_skip}->write(\%files);
818 # we always generate a new MANIFEST instead of allowing existing files to remain
819 # MANIFEST.SKIP is left alone
821 sub ACTION_manifest {
822 my ($self) = @_;
823 if ( -e 'MANIFEST' || -e 'MANIFEST.SKIP' ) {
824 $self->log_warn("MANIFEST files already exist, will overwrite them\n");
825 unlink('MANIFEST');
827 require ExtUtils::Manifest; # ExtUtils::Manifest is not warnings clean.
828 local ($^W, $ExtUtils::Manifest::Quiet) = (0,1);
829 ExtUtils::Manifest::mkmanifest();
832 # extended to add extra things to the default MANIFEST.SKIP
833 #sub _write_default_maniskip {
834 # my $self = shift;
835 # $self->SUPER::_write_default_maniskip;
837 # my @extra = keys %{$self->{phash}{manifest_skip}->read};
838 # if (@extra) {
839 # open(my $fh, '>>', 'MANIFEST.SKIP') or die "Could not open MANIFEST.SKIP file\n";
840 # print $fh "\n# Avoid additional run-time generated things\n";
841 # foreach my $line (@extra) {
842 # print $fh $line, "\n";
844 # close($fh);
848 # extended to run scripts post-installation
849 sub ACTION_install {
850 my ($self) = @_;
851 require ExtUtils::Install;
852 $self->depends_on('build');
853 ExtUtils::Install::install($self->install_map, !$self->quiet, 0, $self->{args}{uninst}||0);
854 #$self->run_post_install_scripts;
857 #sub add_post_install_script {
858 # my $self = shift;
859 # my %files = map {$self->localize_file_path($_), 1} @_;
860 # $self->{phash}{post_install_scripts}->write(\%files);
863 #sub run_post_install_scripts {
864 # my $self = shift;
865 # my @scripts = keys %{$self->{phash}{post_install_scripts}->read};
866 # foreach my $script (@scripts) {
867 # $self->run_perl_script($script);
871 # for use with auto_features, which should require LWP::UserAgent as one of
872 # its reqs
874 # Note: as of 4-11-11, this is no longer called - if someone wants to run
875 # network tests (off by default) w/o a network, then they are hanging themselves
876 # by their own shoelaces.
878 sub test_internet {
879 eval {require LWP::UserAgent;};
880 if ($@) {
881 # ideally this won't happen because auto_feature already specified
882 # LWP::UserAgent, so this sub wouldn't get called if LWP not installed
883 return "LWP::UserAgent not installed";
885 my $ua = LWP::UserAgent->new;
886 $ua->timeout(10);
887 $ua->env_proxy;
888 my $response = $ua->get('http://search.cpan.org/');
889 unless ($response->is_success) {
890 return "Could not connect to the internet (http://search.cpan.org/)";
892 return;
895 # nice directory names for dist-related actions
896 sub dist_dir {
897 my ($self) = @_;
898 my $version = $self->dist_version;
899 if ($version =~ /^\d\.\d{6}\d$/) {
900 # 1.x.x.100 returned as 1.x.x.1
901 $version .= '00';
903 $version =~ s/00(\d)/$1./g;
904 $version =~ s/\.$//;
906 if (my ($minor, $rev) = $version =~ /^\d\.(\d)\.\d\.(\d+)$/) {
907 my $dev = ! ($minor % 2 == 0);
908 if ($rev == 100) {
909 my $replace = $dev ? "_$rev" : '';
910 $version =~ s/\.\d+$/$replace/;
912 elsif ($rev < 100) {
913 $rev = sprintf("%03d", $rev);
914 $version =~ s/\.\d+$/_$rev-RC/;
916 else {
917 $rev -= 100 unless $dev;
918 my $replace = $dev ? "_$rev" : ".$rev";
919 $version =~ s/\.\d+$/$replace/;
923 return "$self->{properties}{dist_name}-$version";
926 # try to be as consistent as possible with Module::Build API
927 #sub ppm_name {
928 # my $self = shift;
929 # return $self->dist_dir.'-ppm';
932 # generate complete ppd4 version file
933 #sub ACTION_ppd {
934 # my $self = shift;
936 # my $file = $self->make_ppd(%{$self->{args}});
937 # $self->add_to_cleanup($file);
938 # #$self->add_to_manifest_skip($file);
941 # add pod2htm temp files to MANIFEST.SKIP, generated during ppmdist most likely
942 #sub htmlify_pods {
943 # my $self = shift;
944 # $self->SUPER::htmlify_pods(@_);
945 # #$self->add_to_manifest_skip('pod2htm*');
948 # don't copy across man3 docs since they're of little use under Windows and
949 # have bad filenames
950 sub ACTION_ppmdist {
951 my $self = shift;
952 my @types = $self->install_types(1);
953 $self->SUPER::ACTION_ppmdist(@_);
954 $self->install_types(0);
957 # when supplied a true value, pretends libdoc doesn't exist (preventing man3
958 # installation for ppmdist). when supplied false, they exist again
959 sub install_types {
960 my ($self, $no_libdoc) = @_;
961 $self->{no_libdoc} = $no_libdoc if defined $no_libdoc;
962 my @types = $self->SUPER::install_types;
963 if ($self->{no_libdoc}) {
964 my @altered_types;
965 foreach my $type (@types) {
966 push(@altered_types, $type) unless $type eq 'libdoc';
968 return @altered_types;
970 return @types;
973 # overridden from Module::Build::PPMMaker for ppd4 compatability
975 # note: no longer needed with more recent versions of Module::Build
977 #sub make_ppd {
978 # my ($self, %args) = @_;
980 # require Module::Build::PPMMaker;
981 # my $mbp = Module::Build::PPMMaker->new();
983 # my %dist;
984 # foreach my $info (qw(name author abstract version)) {
985 # my $method = "dist_$info";
986 # $dist{$info} = $self->$method() or die "Can't determine distribution's $info\n";
988 # $dist{codebase} = $self->ppm_name.'.tar.gz';
989 # $mbp->_simple_xml_escape($_) foreach $dist{abstract}, $dist{codebase}, @{$dist{author}};
991 # my (undef, undef, undef, $mday, $mon, $year) = localtime();
992 # $year += 1900;
993 # $mon++;
994 # my $date = "$year-$mon-$mday";
996 # my $softpkg_version = $self->dist_dir;
997 # $softpkg_version =~ s/^$dist{name}-//;
999 # # to avoid a ppm bug, instead of including the requires in the softpackage
1000 # # for the distribution we're making, we'll make a seperate Bundle::
1001 # # softpackage that contains all the requires, and require only the Bundle in
1002 # # the real softpackage
1003 # my ($bundle_name) = $dist{name} =~ /^.+-(.+)/;
1004 # $bundle_name ||= 'core';
1005 # $bundle_name =~ s/^(\w)/\U$1/;
1006 # my $bundle_dir = "Bundle-BioPerl-$bundle_name-$softpkg_version-ppm";
1007 # my $bundle_file = "$bundle_dir.tar.gz";
1008 # my $bundle_softpkg_name = "Bundle-BioPerl-$bundle_name";
1009 # $bundle_name = "Bundle::BioPerl::$bundle_name";
1011 # # header
1012 # my $ppd = <<"PPD";
1013 # <SOFTPKG NAME=\"$dist{name}\" VERSION=\"$softpkg_version\" DATE=\"$date\">
1014 # <TITLE>$dist{name}</TITLE>
1015 # <ABSTRACT>$dist{abstract}</ABSTRACT>
1016 #@{[ join "\n", map " <AUTHOR>$_</AUTHOR>", @{$dist{author}} ]}
1017 # <PROVIDE NAME=\"$dist{name}::\" VERSION=\"$dist{version}\"/>
1018 #PPD
1020 # # provide section
1021 # foreach my $pm (@{$self->rscan_dir('Bio', qr/\.pm$/)}) {
1022 # # convert these filepaths to Module names
1023 # $pm =~ s/\//::/g;
1024 # $pm =~ s/\.pm//;
1026 # $ppd .= sprintf(<<'EOF', $pm, $dist{version});
1027 # <PROVIDE NAME="%s" VERSION="%s"/>
1028 #EOF
1031 # # rest of softpkg
1032 # $ppd .= <<"PPD";
1033 # <IMPLEMENTATION>
1034 # <ARCHITECTURE NAME=\"MSWin32-x86-multi-thread-5.8\"/>
1035 # <CODEBASE HREF=\"$dist{codebase}\"/>
1036 # <REQUIRE NAME=\"$bundle_name\" VERSION=\"$dist{version}\"/>
1037 # </IMPLEMENTATION>
1038 # </SOFTPKG>
1039 #PPD
1041 # # now a new softpkg for the bundle
1042 # $ppd .= <<"PPD";
1044 # <SOFTPKG NAME=\"$bundle_softpkg_name\" VERSION=\"$softpkg_version\" DATE=\"$date\">
1045 # <TITLE>$bundle_name</TITLE>
1046 # <ABSTRACT>Bundle of pre-requisites for $dist{name}</ABSTRACT>
1047 #@{[ join "\n", map " <AUTHOR>$_</AUTHOR>", @{$dist{author}} ]}
1048 # <PROVIDE NAME=\"$bundle_name\" VERSION=\"$dist{version}\"/>
1049 # <IMPLEMENTATION>
1050 # <ARCHITECTURE NAME=\"MSWin32-x86-multi-thread-5.8\"/>
1051 # <CODEBASE HREF=\"$bundle_file\"/>
1052 #PPD
1054 # # required section
1055 # # we do both requires and recommends to make installation on Windows as
1056 # # easy (mindless) as possible
1057 # for my $type ('requires', 'recommends') {
1058 # my $prereq = $self->$type;
1059 # while (my ($modname, $version) = each %$prereq) {
1060 # next if $modname eq 'perl';
1061 # ($version) = split("/", $version) if $version =~ /\//;
1063 # # Module names must have at least one ::
1064 # unless ($modname =~ /::/) {
1065 # $modname .= '::';
1068 # # Bio::Root::Version number comes out as triplet number like 1.5.2;
1069 # # convert to our own version
1070 # if ($modname eq 'Bio::Root::Version') {
1071 # $version = $dist{version};
1074 # $ppd .= sprintf(<<'EOF', $modname, $version || '');
1075 # <REQUIRE NAME="%s" VERSION="%s"/>
1076 #EOF
1080 # # footer
1081 # $ppd .= <<'EOF';
1082 # </IMPLEMENTATION>
1083 # </SOFTPKG>
1084 #EOF
1086 # my $ppd_file = "$dist{name}.ppd";
1087 # my $fh = IO::File->new(">$ppd_file") or die "Cannot write to $ppd_file: $!";
1088 # print $fh $ppd;
1089 # close $fh;
1091 # $self->delete_filetree($bundle_dir);
1092 # mkdir($bundle_dir) or die "Cannot create '$bundle_dir': $!";
1093 # $self->make_tarball($bundle_dir);
1094 # $self->delete_filetree($bundle_dir);
1095 # $self->add_to_cleanup($bundle_file);
1096 # #$self->add_to_manifest_skip($bundle_file);
1098 # return $ppd_file;
1101 # we make all archive formats we want, not just .tar.gz
1102 # we also auto-run manifest action, since we always want to re-create
1103 # MANIFEST and MANIFEST.SKIP just-in-time
1104 sub ACTION_dist {
1105 my ($self) = @_;
1107 $self->depends_on('manifest');
1108 $self->depends_on('distdir');
1110 my $dist_dir = $self->dist_dir;
1112 $self->make_zip($dist_dir);
1113 $self->make_tarball($dist_dir);
1114 $self->delete_filetree($dist_dir);
1118 # define custom clean/realclean actions to rearrange config file cleanup
1119 sub ACTION_clean {
1120 my ($self) = @_;
1121 $self->log_info("Cleaning up build files\n");
1122 foreach my $item (map glob($_), $self->cleanup) {
1123 $self->delete_filetree($item);
1125 $self->log_info("Cleaning up configuration files\n");
1126 $self->delete_filetree($self->config_dir);
1129 sub ACTION_realclean {
1130 my ($self) = @_;
1131 $self->depends_on('clean');
1132 for my $method (qw(mymetafile mymetafile2 build_script)) {
1133 if ($self->can($method)) {
1134 $self->delete_filetree($self->$method);
1135 $self->log_info("Cleaning up $method data\n");
1140 # makes zip file for windows users and bzip2 files as well
1141 sub make_zip {
1142 my ($self, $dir, $file) = @_;
1143 $file ||= $dir;
1145 $self->log_info("Creating $file.zip\n");
1146 my $zip_flags = $self->verbose ? '-r' : '-rq';
1147 $self->do_system($self->split_like_shell("zip"), $zip_flags, "$file.zip", $dir);
1149 $self->log_info("Creating $file.bz2\n");
1150 require Archive::Tar;
1151 # Archive::Tar versions >= 1.09 use the following to enable a compatibility
1152 # hack so that the resulting archive is compatible with older clients.
1153 $Archive::Tar::DO_NOT_USE_PREFIX = 0;
1154 my $files = $self->rscan_dir($dir);
1155 Archive::Tar->create_archive("$file.tar", 0, @$files);
1156 $self->do_system($self->split_like_shell("bzip2"), "-k", "$file.tar");
1159 # a method that can be called in a Build.PL script to ask the user if they want
1160 # internet tests.
1161 # Should only be called if you have tested for yourself that
1162 # $build->feature('Network') is true
1163 sub prompt_for_network {
1164 my ($self, $accept) = @_;
1166 my $proceed = $accept ? 0 : $self->y_n("Do you want to run tests that require connection to servers across the internet\n(likely to cause some failures)? y/n", 'n');
1168 if ($proceed) {
1169 $self->notes('Network Tests' => 1);
1170 $self->log_info(" - will run internet-requiring tests\n");
1171 my $use_email = $self->y_n("Do you want to run tests requiring a valid email address? y/n",'n');
1172 if ($use_email) {
1173 my $address = $self->prompt("Enter email address:");
1174 $self->notes(email => $address);
1177 else {
1178 $self->notes(network => 0);
1179 $self->log_info(" - will not run internet-requiring tests\n");