Silence the warning "Can't locate auto/POSIX/autosplit.ix in @INC"
[p5sagit/p5-mst-13.2.git] / lib / CPANPLUS / Module.pm
CommitLineData
6aaee015 1package CPANPLUS::Module;
2
3use strict;
4use vars qw[@ISA];
5
6
7use CPANPLUS::Dist;
8use CPANPLUS::Error;
9use CPANPLUS::Module::Signature;
10use CPANPLUS::Module::Checksums;
11use CPANPLUS::Internals::Constants;
12
13use FileHandle;
14
15use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
16use IPC::Cmd qw[can_run run];
17use File::Find qw[find];
18use Params::Check qw[check];
19use Module::Load::Conditional qw[can_load check_install];
20
21$Params::Check::VERBOSE = 1;
22
23@ISA = qw[ CPANPLUS::Module::Signature CPANPLUS::Module::Checksums];
24
25=pod
26
27=head1 NAME
28
29CPANPLUS::Module
30
31=head1 SYNOPSIS
32
33 ### get a module object from the CPANPLUS::Backend object
34 my $mod = $cb->module_tree('Some::Module');
35
36 ### accessors
37 $mod->version;
38 $mod->package;
39
40 ### methods
41 $mod->fetch;
42 $mod->extract;
43 $mod->install;
44
45
46=head1 DESCRIPTION
47
48C<CPANPLUS::Module> creates objects from the information in the
49source files. These can then be used to query and perform actions
50on, like fetching or installing.
51
52These objects should only be created internally. For C<fake> objects,
53there's the C<CPANPLUS::Module::Fake> class. To obtain a module object
54consult the C<CPANPLUS::Backend> documentation.
55
56=cut
57
58my $tmpl = {
59 module => { default => '', required => 1 }, # full module name
60 version => { default => '0.0' }, # version number
61 path => { default => '', required => 1 }, # extended path on the
62 # cpan mirror, like
63 # /author/id/K/KA/KANE
64 comment => { default => ''}, # comment on module
65 package => { default => '', required => 1 }, # package name, like
66 # 'bar-baz-1.03.tgz'
67 description => { default => '' }, # description of the
68 # module
69 dslip => { default => ' ' }, # dslip information
70 _id => { required => 1 }, # id of the Internals
71 # parent object
72 _status => { no_override => 1 }, # stores status object
73 author => { default => '', required => 1,
74 allow => IS_AUTHOBJ }, # module author
75 mtime => { default => '' },
76};
77
78### autogenerate accessors ###
79for my $key ( keys %$tmpl ) {
80 no strict 'refs';
81 *{__PACKAGE__."::$key"} = sub {
82 $_[0]->{$key} = $_[1] if @_ > 1;
83 return $_[0]->{$key};
84 }
85}
86
87=pod
88
89=head1 CLASS METHODS
90
91=head2 accessors ()
92
93Returns a list of all accessor methods to the object
94
95=cut
96
97### *name is an alias, include it explicitly
98sub accessors { return ('name', keys %$tmpl) };
99
100=head1 ACCESSORS
101
102An objects of this class has the following accessors:
103
104=over 4
105
106=item name
107
108Name of the module.
109
110=item module
111
112Name of the module.
113
114=item version
115
116Version of the module. Defaults to '0.0' if none was provided.
117
118=item path
119
120Extended path on the mirror.
121
122=item comment
123
124Any comment about the module -- largely unused.
125
126=item package
127
128The name of the package.
129
130=item description
131
132Description of the module -- only registered modules have this.
133
134=item dslip
135
136The five character dslip string, that represents meta-data of the
137module -- again, only registered modules have this.
138
139=item status
140
141The C<CPANPLUS::Module::Status> object associated with this object.
142(see below).
143
144=item author
145
146The C<CPANPLUS::Module::Author> object associated with this object.
147
148=item parent
149
150The C<CPANPLUS::Internals> object that spawned this module object.
151
152=back
153
154=cut
155
156### Alias ->name to ->module, for human beings.
157*name = *module;
158
159sub parent {
160 my $self = shift;
161 my $obj = CPANPLUS::Internals->_retrieve_id( $self->_id );
162
163 return $obj;
164}
165
166=head1 STATUS ACCESSORS
167
168C<CPANPLUS> caches a lot of results from method calls and saves data
169it collected along the road for later reuse.
170
171C<CPANPLUS> uses this internally, but it is also available for the end
172user. You can get a status object by calling:
173
174 $modobj->status
175
176You can then query the object as follows:
177
178=over 4
179
180=item installer_type
181
182The installer type used for this distribution. Will be one of
183'makemaker' or 'build'. This determines whether C<CPANPLUS::Dist::MM>
184or C<CPANPLUS::Dist::Build> will be used to build this distribution.
185
186=item dist_cpan
187
188The dist object used to do the CPAN-side of the installation. Either
189a C<CPANPLUS::Dist::MM> or C<CPANPLUS::Dist::Build> object.
190
191=item dist
192
193The custom dist object used to do the operating specific side of the
194installation, if you've chosen to use this. For example, if you've
195chosen to install using the C<ports> format, this may be a
196C<CPANPLUS::Dist::Ports> object.
197
198Undefined if you didn't specify a separate format to install through.
199
200=item prereqs
201
202A hashref of prereqs this distribution was found to have. Will look
203something like this:
204
205 { Carp => 0.01, strict => 0 }
206
207Might be undefined if the distribution didn't have any prerequisites.
208
209=item signature
210
211Flag indicating, if a signature check was done, whether it was OK or
212not.
213
214=item extract
215
216The directory this distribution was extracted to.
217
218=item fetch
219
220The location this distribution was fetched to.
221
222=item readme
223
224The text of this distributions README file.
225
226=item uninstall
227
228Flag indicating if an uninstall call was done successfully.
229
230=item created
231
232Flag indicating if the C<create> call to your dist object was done
233successfully.
234
235=item installed
236
237Flag indicating if the C<install> call to your dist object was done
238successfully.
239
240=item checksums
241
242The location of this distributions CHECKSUMS file.
243
244=item checksum_ok
245
246Flag indicating if the checksums check was done successfully.
247
248=item checksum_value
249
250The checksum value this distribution is expected to have
251
252=back
253
254=head1 METHODS
255
256=head2 $self = CPANPLUS::Module::new( OPTIONS )
257
258This method returns a C<CPANPLUS::Module> object. Normal users
259should never call this method directly, but instead use the
260C<CPANPLUS::Backend> to obtain module objects.
261
262This example illustrates a C<new()> call with all required arguments:
263
264 CPANPLUS::Module->new(
265 module => 'Foo',
266 path => 'authors/id/A/AA/AAA',
267 package => 'Foo-1.0.tgz',
268 author => $author_object,
269 _id => INTERNALS_OBJECT_ID,
270 );
271
272Every accessor is also a valid option to pass to C<new>.
273
274Returns a module object on success and false on failure.
275
276=cut
277
278
279sub new {
280 my($class, %hash) = @_;
281
282 ### don't check the template for sanity
283 ### -- we know it's good and saves a lot of performance
284 local $Params::Check::SANITY_CHECK_TEMPLATE = 0;
285
286 my $object = check( $tmpl, \%hash ) or return;
287
288 bless $object, $class;
289
290 return $object;
291}
292
293### only create status objects when they're actually asked for
294sub status {
295 my $self = shift;
296 return $self->_status if $self->_status;
297
298 my $acc = Object::Accessor->new;
299 $acc->mk_accessors( qw[ installer_type dist_cpan dist prereqs
300 signature extract fetch readme uninstall
301 created installed prepared checksums files
302 checksum_ok checksum_value _fetch_from] );
303
304 $self->_status( $acc );
305
306 return $self->_status;
307}
308
309
310### flush the cache of this object ###
311sub _flush {
312 my $self = shift;
313 $self->status->mk_flush;
314 return 1;
315}
316
317=head2 $mod->package_name
318
319Returns the name of the package a module is in. For C<Acme::Bleach>
320that might be C<Acme-Bleach>.
321
322=head2 $mod->package_version
323
324Returns the version of the package a module is in. For a module
325in the package C<Acme-Bleach-1.1.tar.gz> this would be C<1.1>.
326
327=head2 $mod->package_extension
328
329Returns the suffix added by the compression method of a package a
330certain module is in. For a module in C<Acme-Bleach-1.1.tar.gz>, this
331would be C<tar.gz>.
332
333=head2 $mod->package_is_perl_core
334
335Returns a boolean indicating of the package a particular module is in,
336is actually a core perl distribution.
337
338=head2 $mod->module_is_supplied_with_perl_core( [version => $]] )
339
340Returns a boolean indicating whether C<ANY VERSION> of this module
341was supplied with the current running perl's core package.
342
343=head2 $mod->is_bundle
344
345Returns a boolean indicating if the module you are looking at, is
346actually a bundle. Bundles are identified as modules whose name starts
347with C<Bundle::>.
348
349=head2 $mod->is_third_party
350
351Returns a boolean indicating whether the package is a known third-party
352module (i.e. it's not provided by the standard Perl distribution and
353is not available on the CPAN, but on a third party software provider).
354See L<Module::ThirdParty> for more details.
355
356=head2 $mod->third_party_information
357
358Returns a reference to a hash with more information about a third-party
359module. See the documentation about C<module_information()> in
360L<Module::ThirdParty> for more details.
361
362=cut
363
364{ ### fetches the test reports for a certain module ###
365 my %map = (
366 name => 0,
367 version => 1,
368 extension => 2,
369 );
370
371 while ( my($type, $index) = each %map ) {
372 my $name = 'package_' . $type;
373
374 no strict 'refs';
375 *$name = sub {
376 my $self = shift;
377 my @res = $self->parent->_split_package_string(
378 package => $self->package
379 );
380
381 ### return the corresponding index from the result
382 return $res[$index] if @res;
383 return;
384 };
385 }
386
387 sub package_is_perl_core {
388 my $self = shift;
389
390 ### check if the package looks like a perl core package
391 return 1 if $self->package_name eq PERL_CORE;
392
393 my $core = $self->module_is_supplied_with_perl_core;
394 ### ok, so it's found in the core, BUT it could be dual-lifed
395 if ($core) {
396 ### if the package is newer than installed, then it's dual-lifed
397 return if $self->version > $self->installed_version;
398
399 ### if the package is newer or equal to the corelist,
400 ### then it's dual-lifed
401 return if $self->version >= $core;
402
403 ### otherwise, it's older than corelist, thus unsuitable.
404 return 1;
405 }
406
407 ### not in corelist, not a perl core package.
408 return;
409 }
410
411 sub module_is_supplied_with_perl_core {
412 my $self = shift;
413 my $ver = shift || $];
414
415 ### check Module::CoreList to see if it's a core package
416 require Module::CoreList;
417 my $core = $Module::CoreList::version{ $ver }->{ $self->module };
418
419 return $core;
420 }
421
422 ### make sure Bundle-Foo also gets flagged as bundle
423 sub is_bundle {
424 return shift->module =~ /^bundle(?:-|::)/i ? 1 : 0;
425 }
426
427 sub is_third_party {
428 my $self = shift;
429
430 return unless can_load( modules => { 'Module::ThirdParty' => 0 } );
431
432 return Module::ThirdParty::is_3rd_party( $self->name );
433 }
434
435 sub third_party_information {
436 my $self = shift;
437
438 return unless $self->is_third_party;
439
440 return Module::ThirdParty::module_information( $self->name );
441 }
442}
443
444=pod
445
446=head2 $clone = $self->clone
447
448Clones the current module object for tinkering with.
449It will have a clean C<CPANPLUS::Module::Status> object, as well as
450a fake C<CPANPLUS::Module::Author> object.
451
452=cut
453
454sub clone {
455 my $self = shift;
456
457 ### clone the object ###
458 my %data;
459 for my $acc ( grep !/status/, __PACKAGE__->accessors() ) {
460 $data{$acc} = $self->$acc();
461 }
462
463 my $obj = CPANPLUS::Module::Fake->new( %data );
464
465 return $obj;
466}
467
468=pod
469
470=head2 $where = $self->fetch
471
472Fetches the module from a CPAN mirror.
473Look at L<CPANPLUS::Internals::Fetch::_fetch()> for details on the
474options you can pass.
475
476=cut
477
478sub fetch {
479 my $self = shift;
480 my $cb = $self->parent;
481
482 ### custom args
483 my %args = ( module => $self );
484
485 ### if a custom fetch location got specified before, add that here
486 $args{fetch_from} = $self->status->_fetch_from
487 if $self->status->_fetch_from;
488
489 my $where = $cb->_fetch( @_, %args ) or return;
490
491 ### do an md5 check ###
492 if( !$self->status->_fetch_from and
493 $cb->configure_object->get_conf('md5') and
494 $self->package ne CHECKSUMS
495 ) {
496 unless( $self->_validate_checksum ) {
497 error( loc( "Checksum error for '%1' -- will not trust package",
498 $self->package) );
499 return;
500 }
501 }
502
503 return $where;
504}
505
506=pod
507
508=head2 $path = $self->extract
509
510Extracts the fetched module.
511Look at L<CPANPLUS::Internals::Extract::_extract()> for details on
512the options you can pass.
513
514=cut
515
516sub extract {
517 my $self = shift;
518 my $cb = $self->parent;
519
520 unless( $self->status->fetch ) {
521 error( loc( "You have not fetched '%1' yet -- cannot extract",
522 $self->module) );
523 return;
524 }
525
526 return $cb->_extract( @_, module => $self );
527}
528
529=head2 $type = $self->get_installer_type([prefer_makefile => BOOL])
530
531Gets the installer type for this module. This may either be C<build> or
532C<makemaker>. If C<Module::Build> is unavailable or no installer type
533is available, it will fall back to C<makemaker>. If both are available,
534it will pick the one indicated by your config, or by the
535C<prefer_makefile> option you can pass to this function.
536
537Returns the installer type on success, and false on error.
538
539=cut
540
541sub get_installer_type {
542 my $self = shift;
543 my $cb = $self->parent;
544 my $conf = $cb->configure_object;
545 my %hash = @_;
546
547 my $prefer_makefile;
548 my $tmpl = {
549 prefer_makefile => { default => $conf->get_conf('prefer_makefile'),
550 store => \$prefer_makefile, allow => BOOLEANS },
551 };
552
553 check( $tmpl, \%hash ) or return;
554
555 my $extract = $self->status->extract();
556 unless( $extract ) {
557 error(loc("Cannot determine installer type of unextracted module '%1'",
558 $self->module));
559 return;
560 }
561
562
563 ### check if it's a makemaker or a module::build type dist ###
564 my $found_build = -e BUILD_PL->( $extract );
565 my $found_makefile = -e MAKEFILE_PL->( $extract );
566
567 my $type;
568 $type = INSTALLER_BUILD if !$prefer_makefile && $found_build;
569 $type = INSTALLER_BUILD if $found_build && !$found_makefile;
570 $type = INSTALLER_MM if $prefer_makefile && $found_makefile;
571 $type = INSTALLER_MM if $found_makefile && !$found_build;
572
573 ### ok, so it's a 'build' installer, but you don't /have/ module build
574 if( $type eq INSTALLER_BUILD and (
575 not grep { $_ eq INSTALLER_BUILD } CPANPLUS::Dist->dist_types )
576 ) {
577 error( loc( "This module requires '%1' and '%2' to be installed, ".
578 "but you don't have it! Will fall back to ".
579 "'%3', but might not be able to install!",
580 'Module::Build', INSTALLER_BUILD, INSTALLER_MM ) );
581 $type = INSTALLER_MM;
582
583 ### ok, actually we found neither ###
584 } elsif ( !$type ) {
585 error( loc( "Unable to find '%1' or '%2' for '%3'; ".
586 "Will default to '%4' but might be unable ".
587 "to install!", BUILD_PL->(), MAKEFILE_PL->(),
588 $self->module, INSTALLER_MM ) );
589 $type = INSTALLER_MM;
590 }
591
592 return $self->status->installer_type( $type ) if $type;
593 return;
594}
595
596=pod
597
598=head2 $dist = $self->dist([target => 'prepare|create', format => DISTRIBUTION_TYPE, args => {key => val}]);
599
600Create a distribution object, ready to be installed.
601Distribution type defaults to your config settings
602
603The optional C<args> hashref is passed on to the specific distribution
604types' C<create> method after being dereferenced.
605
606Returns a distribution object on success, false on failure.
607
608See C<CPANPLUS::Dist> for details.
609
610=cut
611
612sub dist {
613 my $self = shift;
614 my $cb = $self->parent;
615 my $conf = $cb->configure_object;
616 my %hash = @_;
617
618 ### have you determined your installer type yet? if not, do it here,
619 ### we need the info
620 $self->get_installer_type unless $self->status->installer_type;
621
622
623 my($type,$args,$target);
624 my $tmpl = {
625 format => { default => $conf->get_conf('dist_type') ||
626 $self->status->installer_type,
627 store => \$type },
628 target => { default => TARGET_CREATE, store => \$target },
629 args => { default => {}, store => \$args },
630 };
631
632 check( $tmpl, \%hash ) or return;
633
634 my $dist = CPANPLUS::Dist->new(
635 format => $type,
636 module => $self
637 ) or return;
638
639 my $dist_cpan = $type eq $self->status->installer_type
640 ? $dist
641 : CPANPLUS::Dist->new(
642 format => $self->status->installer_type,
643 module => $self,
644 );
645
646 ### store the dists
647 $self->status->dist_cpan( $dist_cpan );
648 $self->status->dist( $dist );
649
650 DIST: {
651 ### first prepare the dist
652 $dist->prepare( %$args ) or return;
653 $self->status->prepared(1);
654
655 ### you just wanted us to prepare?
656 last DIST if $target eq TARGET_PREPARE;
657
658 $dist->create( %$args ) or return;
659 $self->status->created(1);
660 }
661
662 return $dist;
663}
664
665=pod
666
667=head2 $bool = $mod->prepare( )
668
669Convenience method around C<install()> that prepares a module
670without actually building it. This is equivalent to invoking C<install>
671with C<target> set to C<prepare>
672
673Returns true on success, false on failure.
674
675=cut
676
677sub prepare {
678 my $self = shift;
679 return $self->install( @_, target => TARGET_PREPARE );
680}
681
682=head2 $bool = $mod->create( )
683
684Convenience method around C<install()> that creates a module.
685This is equivalent to invoking C<install> with C<target> set to
686C<create>
687
688Returns true on success, false on failure.
689
690=cut
691
692sub create {
693 my $self = shift;
694 return $self->install( @_, target => TARGET_CREATE );
695}
696
697=head2 $bool = $mod->test( )
698
699Convenience wrapper around C<install()> that tests a module, without
700installing it.
701It's the equivalent to invoking C<install()> with C<target> set to
702C<create> and C<skiptest> set to C<0>.
703
704Returns true on success, false on failure.
705
706=cut
707
708sub test {
709 my $self = shift;
710 return $self->install( @_, target => TARGET_CREATE, skiptest => 0 );
711}
712
713=pod
714
715=head2 $bool = $self->install([ target => 'prepare|create|install', format => FORMAT_TYPE, extractdir => DIRECTORY, fetchdir => DIRECTORY, prefer_bin => BOOL, force => BOOL, verbose => BOOL, ..... ]);
716
717Installs the current module. This includes fetching it and extracting
718it, if this hasn't been done yet, as well as creating a distribution
719object for it.
720
721This means you can pass it more arguments than described above, which
722will be passed on to the relevant methods as they are called.
723
724See C<CPANPLUS::Internals::Fetch>, C<CPANPLUS::Internals::Extract> and
725C<CPANPLUS::Dist> for details.
726
727Returns true on success, false on failure.
728
729=cut
730
731sub install {
732 my $self = shift;
733 my $cb = $self->parent;
734 my $conf = $cb->configure_object;
735 my %hash = @_;
736
737 my $args; my $target; my $format;
738 { ### so we can use the rest of the args to the create calls etc ###
739 local $Params::Check::NO_DUPLICATES = 1;
740 local $Params::Check::ALLOW_UNKNOWN = 1;
741
742 ### targets 'dist' and 'test' are now completely ignored ###
743 my $tmpl = {
744 ### match this allow list with Dist->_resolve_prereqs
745 target => { default => TARGET_INSTALL, store => \$target,
746 allow => [TARGET_PREPARE, TARGET_CREATE,
747 TARGET_INSTALL] },
748 force => { default => $conf->get_conf('force'), },
749 verbose => { default => $conf->get_conf('verbose'), },
750 format => { default => $conf->get_conf('dist_type'),
751 store => \$format },
752 };
753
754 $args = check( $tmpl, \%hash ) or return;
755 }
756
757
758 ### if this target isn't 'install', we will need to at least 'create'
759 ### every prereq, so it can build
760 ### XXX prereq_target of 'prepare' will do weird things here, and is
761 ### not supported.
762 $args->{'prereq_target'} ||= TARGET_CREATE if $target ne TARGET_INSTALL;
763
764 ### check if it's already upto date ###
765 if( $target eq TARGET_INSTALL and !$args->{'force'} and
766 !$self->package_is_perl_core() and # separate rules apply
767 ( $self->status->installed() or $self->is_uptodate ) and
768 !INSTALL_VIA_PACKAGE_MANAGER->($format)
769 ) {
770 msg(loc("Module '%1' already up to date, won't install without force",
771 $self->module), $args->{'verbose'} );
772 return $self->status->installed(1);
773 }
774
775 # if it's a non-installable core package, abort the install.
776 if( $self->package_is_perl_core() ) {
777 # if the installed is newer, say so.
778 if( $self->installed_version > $self->version ) {
779 error(loc("The core Perl %1 module '%2' (%3) is more ".
780 "recent than the latest release on CPAN (%4). ".
781 "Aborting install.",
782 $], $self->module, $self->installed_version,
783 $self->version ) );
784 # if the installed matches, say so.
785 } elsif( $self->installed_version == $self->version ) {
786 error(loc("The core Perl %1 module '%2' (%3) can only ".
787 "be installed by Perl itself. ".
788 "Aborting install.",
789 $], $self->module, $self->installed_version ) );
790 # otherwise, the installed is older; say so.
791 } else {
792 error(loc("The core Perl %1 module '%2' can only be ".
793 "upgraded from %3 to %4 by Perl itself (%5). ".
794 "Aborting install.",
795 $], $self->module, $self->installed_version,
796 $self->version, $self->package ) );
797 }
798 return;
799
800 ### it might be a known 3rd party module
801 } elsif ( $self->is_third_party ) {
802 my $info = $self->third_party_information;
803 error(loc(
804 "%1 is a known third-party module.\n\n".
805 "As it isn't available on the CPAN, CPANPLUS can't install " .
806 "it automatically. Therefore you need to install it manually " .
807 "before proceeding.\n\n".
808 "%2 is part of %3, published by %4, and should be available ".
809 "for download at the following address:\n\t%5",
810 $self->name, $self->name, $info->{name}, $info->{author},
811 $info->{url}
812 ));
813
814 return;
815 }
816
817 ### fetch it if need be ###
818 unless( $self->status->fetch ) {
819 my $params;
820 for (qw[prefer_bin fetchdir]) {
821 $params->{$_} = $args->{$_} if exists $args->{$_};
822 }
823 for (qw[force verbose]) {
824 $params->{$_} = $args->{$_} if defined $args->{$_};
825 }
826 $self->fetch( %$params ) or return;
827 }
828
829 ### extract it if need be ###
830 unless( $self->status->extract ) {
831 my $params;
832 for (qw[prefer_bin extractdir]) {
833 $params->{$_} = $args->{$_} if exists $args->{$_};
834 }
835 for (qw[force verbose]) {
836 $params->{$_} = $args->{$_} if defined $args->{$_};
837 }
838 $self->extract( %$params ) or return;
839 }
840
841 $format ||= $self->status->installer_type;
842
843 unless( $format ) {
844 error( loc( "Don't know what installer to use; " .
845 "Couldn't find either '%1' or '%2' in the extraction " .
846 "directory '%3' -- will be unable to install",
847 BUILD_PL->(), MAKEFILE_PL->(), $self->status->extract ) );
848
849 $self->status->installed(0);
850 return;
851 }
852
853
854 ### do SIGNATURE checks? ###
855 if( $conf->get_conf('signature') ) {
856 unless( $self->check_signature( verbose => $args->{verbose} ) ) {
857 error( loc( "Signature check failed for module '%1' ".
858 "-- Not trusting this module, aborting install",
859 $self->module ) );
860 $self->status->signature(0);
861
862 ### send out test report on broken sig
863 if( $conf->get_conf('cpantest') ) {
864 $cb->_send_report(
865 module => $self,
866 failed => 1,
867 buffer => CPANPLUS::Error->stack_as_string,
868 verbose => $args->{verbose},
869 force => $args->{force},
870 ) or error(loc("Failed to send test report for '%1'",
871 $self->module ) );
872 }
873
874 return;
875
876 } else {
877 ### signature OK ###
878 $self->status->signature(1);
879 }
880 }
881
882 ### a target of 'create' basically means not to run make test ###
883 ### eh, no it /doesn't/.. skiptest => 1 means skiptest => 1.
884 #$args->{'skiptest'} = 1 if $target eq 'create';
885
886 ### bundle rules apply ###
887 if( $self->is_bundle ) {
888 ### check what we need to install ###
889 my @prereqs = $self->bundle_modules();
890 unless( @prereqs ) {
891 error( loc( "Bundle '%1' does not specify any modules to install",
892 $self->module ) );
893
894 ### XXX mark an error here? ###
895 }
896 }
897
898 my $dist = $self->dist( format => $format,
899 target => $target,
900 args => $args );
901 unless( $dist ) {
902 error( loc( "Unable to create a new distribution object for '%1' " .
903 "-- cannot continue", $self->module ) );
904 return;
905 }
906
907 return 1 if $target ne TARGET_INSTALL;
908
909 my $ok = $dist->install( %$args ) ? 1 : 0;
910
911 $self->status->installed($ok);
912
913 return 1 if $ok;
914 return;
915}
916
917=pod @list = $self->bundle_modules()
918
919Returns a list of module objects the Bundle specifies.
920
921This requires you to have extracted the bundle already, using the
922C<extract()> method.
923
924Returns false on error.
925
926=cut
927
928sub bundle_modules {
929 my $self = shift;
930 my $cb = $self->parent;
931
932 unless( $self->is_bundle ) {
933 error( loc("'%1' is not a bundle", $self->module ) );
934 return;
935 }
936
937 my $dir;
938 unless( $dir = $self->status->extract ) {
939 error( loc("Don't know where '%1' was extracted to", $self->module ) );
940 return;
941 }
942
943 my @files;
944 find( {
945 wanted => sub { push @files, File::Spec->rel2abs($_) if /\.pm/i; },
946 no_chdir => 1,
947 }, $dir );
948
949 my $prereqs = {}; my @list; my $seen = {};
950 for my $file ( @files ) {
951 my $fh = FileHandle->new($file)
952 or( error(loc("Could not open '%1' for reading: %2",
953 $file,$!)), next );
954
955 my $flag;
956 while(<$fh>) {
957 ### quick hack to read past the header of the file ###
958 last if $flag && m|^=head|i;
959
960 ### from perldoc cpan:
961 ### =head1 CONTENTS
962 ### In this pod section each line obeys the format
963 ### Module_Name [Version_String] [- optional text]
964 $flag = 1 if m|^=head1 CONTENTS|i;
965
966 if ($flag && /^(?!=)(\S+)\s*(\S+)?/) {
967 my $module = $1;
968 my $version = $2 || '0';
969
970 my $obj = $cb->module_tree($module);
971
972 unless( $obj ) {
973 error(loc("Cannot find bundled module '%1'", $module),
974 loc("-- it does not seem to exist") );
975 next;
976 }
977
978 ### make sure we list no duplicates ###
979 unless( $seen->{ $obj->module }++ ) {
980 push @list, $obj;
981 $prereqs->{ $module } =
982 $cb->_version_to_number( version => $version );
983 }
984 }
985 }
986 }
987
988 ### store the prereqs we just found ###
989 $self->status->prereqs( $prereqs );
990
991 return @list;
992}
993
994=pod
995
996=head2 $text = $self->readme
997
998Fetches the readme belonging to this module and stores it under
999C<< $obj->status->readme >>. Returns the readme as a string on
1000success and returns false on failure.
1001
1002=cut
1003
1004sub readme {
1005 my $self = shift;
1006 my $conf = $self->parent->configure_object;
1007
1008 ### did we already dl the readme once? ###
1009 return $self->status->readme() if $self->status->readme();
1010
1011 ### this should be core ###
1012 return unless can_load( modules => { FileHandle => '0.0' },
1013 verbose => 1,
1014 );
1015
1016 ### get a clone of the current object, with a fresh status ###
1017 my $obj = $self->clone or return;
1018
1019 ### munge the package name
1020 my $pkg = README->( $obj );
1021 $obj->package($pkg);
1022
1023 my $file;
1024 { ### disable checksum fetches on readme downloads
1025
1026 my $tmp = $conf->get_conf( 'md5' );
1027 $conf->set_conf( md5 => 0 );
1028
1029 $file = $obj->fetch;
1030
1031 $conf->set_conf( md5 => $tmp );
1032
1033 return unless $file;
1034 }
1035
1036 ### read the file into a scalar, to store in the original object ###
1037 my $fh = new FileHandle;
1038 unless( $fh->open($file) ) {
1039 error( loc( "Could not open file '%1': %2", $file, $! ) );
1040 return;
1041 }
1042
1043 my $in;
1044 { local $/; $in = <$fh> };
1045 $fh->close;
1046
1047 return $self->status->readme( $in );
1048}
1049
1050=pod
1051
1052=head2 $version = $self->installed_version()
1053
1054Returns the currently installed version of this module, if any.
1055
1056=head2 $where = $self->installed_file()
1057
1058Returns the location of the currently installed file of this module,
1059if any.
1060
1061=head2 $bool = $self->is_uptodate([version => VERSION_NUMBER])
1062
1063Returns a boolean indicating if this module is uptodate or not.
1064
1065=cut
1066
1067### uptodate/installed functions
1068{ my $map = { # hashkey, alternate rv
1069 installed_version => ['version', 0 ],
1070 installed_file => ['file', ''],
1071 is_uptodate => ['uptodate', 0 ],
1072 };
1073
1074 while( my($method, $aref) = each %$map ) {
1075 my($key,$alt_rv) = @$aref;
1076
1077 no strict 'refs';
1078 *$method = sub {
1079 ### never use the @INC hooks to find installed versions of
1080 ### modules -- they're just there in case they're not on the
1081 ### perl install, but the user shouldn't trust them for *other*
1082 ### modules!
1083 ### XXX CPANPLUS::inc is now obsolete, so this should not
1084 ### be needed anymore
1085 #local @INC = CPANPLUS::inc->original_inc;
1086
1087 my $self = shift;
1088
1089 ### make sure check_install is not looking in %INC, as
1090 ### that may contain some of our sneakily loaded modules
1091 ### that aren't installed as such. -- kane
1092 local $Module::Load::Conditional::CHECK_INC_HASH = 0;
1093 my $href = check_install(
1094 module => $self->module,
1095 version => $self->version,
1096 @_,
1097 );
1098
1099 return $href->{$key} || $alt_rv;
1100 }
1101 }
1102}
1103
1104
1105
1106=pod
1107
1108=head2 $href = $self->details()
1109
1110Returns a hashref with key/value pairs offering more information about
1111a particular module. For example, for C<Time::HiRes> it might look like
1112this:
1113
1114 Author Jarkko Hietaniemi (jhi@iki.fi)
1115 Description High resolution time, sleep, and alarm
1116 Development Stage Released
1117 Installed File /usr/local/perl/lib/Time/Hires.pm
1118 Interface Style plain Functions, no references used
1119 Language Used C and perl, a C compiler will be needed
1120 Package Time-HiRes-1.65.tar.gz
1121 Public License Unknown
1122 Support Level Developer
1123 Version Installed 1.52
1124 Version on CPAN 1.65
1125
1126=cut
1127
1128sub details {
1129 my $self = shift;
1130 my $conf = $self->parent->configure_object();
1131 my $cb = $self->parent;
1132 my %hash = @_;
1133
1134 my $res = {
1135 Author => loc("%1 (%2)", $self->author->author(),
1136 $self->author->email() ),
1137 Package => $self->package,
1138 Description => $self->description || loc('None given'),
1139 'Version on CPAN' => $self->version,
1140 };
1141
1142 ### check if we have the module installed
1143 ### if so, add version have and version on cpan
1144 $res->{'Version Installed'} = $self->installed_version
1145 if $self->installed_version;
1146 $res->{'Installed File'} = $self->installed_file if $self->installed_file;
1147
1148 my $i = 0;
1149 for my $item( split '', $self->dslip ) {
1150 $res->{ $cb->_dslip_defs->[$i]->[0] } =
1151 $cb->_dslip_defs->[$i]->[1]->{$item} || loc('Unknown');
1152 $i++;
1153 }
1154
1155 return $res;
1156}
1157
1158=head2 @list = $self->contains()
1159
1160Returns a list of module objects that represent the modules also
1161present in the package of this module.
1162
1163For example, for C<Archive::Tar> this might return:
1164
1165 Archive::Tar
1166 Archive::Tar::Constant
1167 Archive::Tar::File
1168
1169=cut
1170
1171sub contains {
1172 my $self = shift;
1173 my $cb = $self->parent;
1174 my $pkg = $self->package;
1175
1176 my @mods = $cb->search( type => 'package', allow => [qr/^$pkg$/] );
1177
1178 return @mods;
1179}
1180
1181=pod
1182
1183=head2 @list_of_hrefs = $self->fetch_report()
1184
1185This function queries the CPAN testers database at
1186I<http://testers.cpan.org/> for test results of specified module
1187objects, module names or distributions.
1188
1189Look at L<CPANPLUS::Internals::Report::_query_report()> for details on
1190the options you can pass and the return value to expect.
1191
1192=cut
1193
1194sub fetch_report {
1195 my $self = shift;
1196 my $cb = $self->parent;
1197
1198 return $cb->_query_report( @_, module => $self );
1199}
1200
1201=pod
1202
1203=head2 $bool = $self->uninstall([type => [all|man|prog])
1204
1205This function uninstalls the specified module object.
1206
1207You can install 2 types of files, either C<man> pages or C<prog>ram
1208files. Alternately you can specify C<all> to uninstall both (which
1209is the default).
1210
1211Returns true on success and false on failure.
1212
1213Do note that this does an uninstall via the so-called C<.packlist>,
1214so if you used a module installer like say, C<ports> or C<apt>, you
1215should not use this, but use your package manager instead.
1216
1217=cut
1218
1219sub uninstall {
1220 my $self = shift;
1221 my $conf = $self->parent->configure_object();
1222 my %hash = @_;
1223
1224 my ($type,$verbose);
1225 my $tmpl = {
1226 type => { default => 'all', allow => [qw|man prog all|],
1227 store => \$type },
1228 verbose => { default => $conf->get_conf('verbose'),
1229 store => \$verbose },
1230 force => { default => $conf->get_conf('force') },
1231 };
1232
1233 ### XXX add a warning here if your default install dist isn't
1234 ### makefile or build -- that means you are using a package manager
1235 ### and this will not do what you think!
1236
1237 my $args = check( $tmpl, \%hash ) or return;
1238
1239 if( $conf->get_conf('dist_type') and (
1240 ($conf->get_conf('dist_type') ne INSTALLER_BUILD) or
1241 ($conf->get_conf('dist_type') ne INSTALLER_MM))
1242 ) {
1243 msg(loc("You have a default installer type set (%1) ".
1244 "-- you should probably use that package manager to " .
1245 "uninstall modules", $conf->get_conf('dist_type')), $verbose);
1246 }
1247
1248 ### check if we even have the module installed -- no point in continuing
1249 ### otherwise
1250 unless( $self->installed_version ) {
1251 error( loc( "Module '%1' is not installed, so cannot uninstall",
1252 $self->module ) );
1253 return;
1254 }
1255
1256 ### nothing to uninstall ###
1257 my $files = $self->files( type => $type ) or return;
1258 my $dirs = $self->directory_tree( type => $type ) or return;
1259 my $sudo = $conf->get_program('sudo');
1260
1261 ### just in case there's no file; M::B doensn't provide .packlists yet ###
1262 my $pack = $self->packlist;
1263 $pack = $pack->[0]->packlist_file() if $pack;
1264
1265 ### first remove the files, then the dirs if they are empty ###
1266 my $flag = 0;
1267 for my $file( @$files, $pack ) {
1268 next unless defined $file && -f $file;
1269
1270 msg(loc("Unlinking '%1'", $file), $verbose);
1271
1272 my @cmd = ($^X, "-eunlink+q[$file]");
1273 unshift @cmd, $sudo if $sudo;
1274
1275 my $buffer;
1276 unless ( run( command => \@cmd,
1277 verbose => $verbose,
1278 buffer => \$buffer )
1279 ) {
1280 error(loc("Failed to unlink '%1': '%2'",$file, $buffer));
1281 $flag++;
1282 }
1283 }
1284
1285 for my $dir ( sort @$dirs ) {
1286 local *DIR;
1287 open DIR, $dir or next;
1288 my @count = readdir(DIR);
1289 close DIR;
1290
1291 next unless @count == 2; # . and ..
1292
1293 msg(loc("Removing '%1'", $dir), $verbose);
1294
1295 ### this fails on my win2k machines.. it indeed leaves the
1296 ### dir, but it's not a critical error, since the files have
1297 ### been removed. --kane
1298 #unless( rmdir $dir ) {
1299 # error( loc( "Could not remove '%1': %2", $dir, $! ) )
1300 # unless $^O eq 'MSWin32';
1301 #}
1302
1303 my @cmd = ($^X, "-ermdir+q[$dir]");
1304 unshift @cmd, $sudo if $sudo;
1305
1306 my $buffer;
1307 unless ( run( command => \@cmd,
1308 verbose => $verbose,
1309 buffer => \$buffer )
1310 ) {
1311 error(loc("Failed to rmdir '%1': %2",$dir,$buffer));
1312 $flag++;
1313 }
1314 }
1315
1316 $self->status->uninstall(!$flag);
1317 $self->status->installed( $flag ? 1 : undef);
1318
1319 return !$flag;
1320}
1321
1322=pod
1323
1324=head2 @modobj = $self->distributions()
1325
1326Returns a list of module objects representing all releases for this
1327module on success, false on failure.
1328
1329=cut
1330
1331sub distributions {
1332 my $self = shift;
1333 my %hash = @_;
1334
1335 my @list = $self->author->distributions( %hash, module => $self ) or return;
1336
1337 ### it's another release then by the same author ###
1338 return grep { $_->package_name eq $self->package_name } @list;
1339}
1340
1341=pod
1342
1343=head2 @list = $self->files ()
1344
1345Returns a list of files used by this module, if it is installed.
1346
1347=cut
1348
1349sub files {
1350 return shift->_extutils_installed( @_, method => 'files' );
1351}
1352
1353=pod
1354
1355=head2 @list = $self->directory_tree ()
1356
1357Returns a list of directories used by this module.
1358
1359=cut
1360
1361sub directory_tree {
1362 return shift->_extutils_installed( @_, method => 'directory_tree' );
1363}
1364
1365=pod
1366
1367=head2 @list = $self->packlist ()
1368
1369Returns the C<ExtUtils::Packlist> object for this module.
1370
1371=cut
1372
1373sub packlist {
1374 return shift->_extutils_installed( @_, method => 'packlist' );
1375}
1376
1377=pod
1378
1379=head2 @list = $self->validate ()
1380
1381Returns a list of files that are missing for this modules, but
1382are present in the .packlist file.
1383
1384=cut
1385
1386sub validate {
1387 return shift->_extutils_installed( method => 'validate' );
1388}
1389
1390### generic method to call an ExtUtils::Installed method ###
1391sub _extutils_installed {
1392 my $self = shift;
1393 my $conf = $self->parent->configure_object();
1394 my %hash = @_;
1395
1396 my ($verbose,$type,$method);
1397 my $tmpl = {
1398 verbose => { default => $conf->get_conf('verbose'),
1399 store => \$verbose, },
1400 type => { default => 'all',
1401 allow => [qw|prog man all|],
1402 store => \$type, },
1403 method => { required => 1,
1404 store => \$method,
1405 allow => [qw|files directory_tree packlist
1406 validate|],
1407 },
1408 };
1409
1410 my $args = check( $tmpl, \%hash ) or return;
1411
1412 ### old versions of cygwin + perl < 5.8 are buggy here. bail out if we
1413 ### find we're being used by them
1414 { my $err = ON_OLD_CYGWIN;
1415 if($err) { error($err); return };
1416 }
1417
1418 return unless can_load(
1419 modules => { 'ExtUtils::Installed' => '0.0' },
1420 verbose => $verbose,
1421 );
1422
1423 my $inst;
1424 unless( $inst = ExtUtils::Installed->new() ) {
1425 error( loc("Could not create an '%1' object", 'ExtUtils::Installed' ) );
1426
1427 ### in case it's being used directly... ###
1428 return;
1429 }
1430
1431
1432 { ### EU::Installed can die =/
1433 my @files;
1434 eval { @files = $inst->$method( $self->module, $type ) };
1435
1436 if( $@ ) {
1437 chomp $@;
1438 error( loc("Could not get '%1' for '%2': %3",
1439 $method, $self->module, $@ ) );
1440 return;
1441 }
1442
1443 return wantarray ? @files : \@files;
1444 }
1445}
1446
1447=head2 $bool = $self->add_to_includepath;
1448
1449Adds the current modules path to C<@INC> and C<$PERL5LIB>. This allows
1450you to add the module from it's build dir to your path.
1451
1452You can reset C<@INC> and C<$PERL5LIB> to it's original state when you
1453started the program, by calling:
1454
1455 $self->parent->flush('lib');
1456
1457=cut
1458
1459sub add_to_includepath {
1460 my $self = shift;
1461 my $cb = $self->parent;
1462
1463 if( my $dir = $self->status->extract ) {
1464
1465 $cb->_add_to_includepath(
1466 directories => [
1467 File::Spec->catdir(BLIB->($dir), LIB),
1468 File::Spec->catdir(BLIB->($dir), ARCH),
1469 BLIB->($dir),
1470 ]
1471 ) or return;
1472
1473 } else {
1474 error(loc( "No extract dir registered for '%1' -- can not add ".
1475 "add builddir to search path!", $self->module ));
1476 return;
1477 }
1478
1479 return 1;
1480
1481}
1482
1483=pod
1484
1485=head2 $path = $self->best_path_to_module_build();
1486
1487B<OBSOLETE>
1488
1489If a newer version of Module::Build is found in your path, it will
1490return this C<special> path. If the newest version of C<Module::Build>
1491is found in your regular C<@INC>, the method will return false. This
1492indicates you do not need to add a special directory to your C<@INC>.
1493
1494Note that this is only relevant if you're building your own
1495C<CPANPLUS::Dist::*> plugin -- the built-in dist types already have
1496this taken care of.
1497
1498=cut
1499
1500### make sure we're always running 'perl Build.PL' and friends
1501### against the highest version of module::build available
1502sub best_path_to_module_build {
1503 my $self = shift;
1504
1505 ### Since M::B will actually shell out and run the Build.PL, we must
1506 ### make sure it refinds the proper version of M::B in the path.
1507 ### that may be either in our cp::inc or in site_perl, or even a
1508 ### new M::B being installed.
1509 ### don't add anything else here, as that might screw up prereq checks
1510
1511 ### XXX this might be needed for Dist::MM too, if a makefile.pl is
1512 ### masquerading as a Build.PL
1513
1514 ### did we find the most recent module::build in our installer path?
1515
1516 ### XXX can't do changes to @INC, they're being ignored by
1517 ### new_from_context when writing a Build script. see ticket:
1518 ### #8826 Module::Build ignores changes to @INC when writing Build
1519 ### from new_from_context
1520 ### XXX applied schwern's patches (as seen on CPANPLUS::Devel 10/12/04)
1521 ### and upped the version to 0.26061 of the bundled version, and things
1522 ### work again
1523
1524 ### this functionality is now obsolete -- prereqs should be installed
1525 ### and we no longer use the CPANPLUS::inc magic.. so comment this out.
1526# require Module::Build;
1527# if( CPANPLUS::inc->path_to('Module::Build') and (
1528# CPANPLUS::inc->path_to('Module::Build') eq
1529# CPANPLUS::inc->installer_path )
1530# ) {
1531#
1532# ### if the module being installed is *not* Module::Build
1533# ### itself -- as that would undoubtedly be newer -- add
1534# ### the path to the installers to @INC
1535# ### if it IS module::build itself, add 'lib' to its path,
1536# ### as the Build.PL would do as well, but the API doesn't.
1537# ### this makes self updates possible
1538# return $self->module eq 'Module::Build'
1539# ? 'lib'
1540# : CPANPLUS::inc->installer_path;
1541# }
1542
1543 ### otherwise, the path was found through a 'normal' way of
1544 ### scanning @INC.
1545 return;
1546}
1547
1548=pod
1549
1550=head1 BUG REPORTS
1551
1552Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>.
1553
1554=head1 AUTHOR
1555
1556This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
1557
1558=head1 COPYRIGHT
1559
1560The CPAN++ interface (of which this module is a part of) is copyright (c)
15612001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved.
1562
1563This library is free software; you may redistribute and/or modify it
1564under the same terms as Perl itself.
1565
1566=cut
1567
1568# Local variables:
1569# c-indentation-style: bsd
1570# c-basic-offset: 4
1571# indent-tabs-mode: nil
1572# End:
1573# vim: expandtab shiftwidth=4:
1574
15751;
1576
1577__END__
1578
1579todo:
1580reports();