1 package CPANPLUS::Backend;
7 use CPANPLUS::Configure;
8 use CPANPLUS::Internals;
9 use CPANPLUS::Internals::Constants;
11 use CPANPLUS::Module::Author;
12 use CPANPLUS::Backend::RV;
16 use File::Spec::Unix ();
17 use File::Basename ();
18 use Params::Check qw[check];
19 use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
21 $Params::Check::VERBOSE = 1;
23 use vars qw[@ISA $VERSION];
25 @ISA = qw[CPANPLUS::Internals];
26 $VERSION = $CPANPLUS::Internals::VERSION;
28 ### mark that we're running under CPANPLUS to spawned processes
29 $ENV{'PERL5_CPANPLUS_IS_RUNNING'} = $$;
31 ### XXX version.pm MAY format this version, if it's in use... :(
32 ### so for consistency, just call ->VERSION ourselves as well.
33 $ENV{'PERL5_CPANPLUS_IS_VERSION'} = __PACKAGE__->VERSION;
43 my $cb = CPANPLUS::Backend->new;
44 my $conf = $cb->configure_object;
46 my $author = $cb->author_tree('KANE');
47 my $mod = $cb->module_tree('Some::Module');
48 my $mod = $cb->parse_module( module => 'Some::Module' );
50 my @objs = $cb->search( type => TYPE,
60 This module provides the programmer's interface to the C<CPANPLUS>
65 When C<CPANPLUS::Backend> is loaded, which is necessary for just
66 about every <CPANPLUS> operation, the environment variable
67 C<PERL5_CPANPLUS_IS_RUNNING> is set to the current process id.
69 Additionally, the environment variable C<PERL5_CPANPLUS_IS_VERSION>
70 will be set to the version of C<CPANPLUS::Backend>.
72 This information might be useful somehow to spawned processes.
76 =head2 $cb = CPANPLUS::Backend->new( [CONFIGURE_OBJ] )
78 This method returns a new C<CPANPLUS::Backend> object.
79 This also initialises the config corresponding to this object.
80 You have two choices in this:
84 =item Provide a valid C<CPANPLUS::Configure> object
86 This will be used verbatim.
90 Your default config will be loaded and used.
94 New will return a C<CPANPLUS::Backend> object on success and die on
103 if( $_[0] && IS_CONFOBJ->( conf => $_[0] ) ) {
106 $conf = CPANPLUS::Configure->new() or return;
109 my $self = $class->SUPER::_init( _conf => $conf );
116 =head2 $href = $cb->module_tree( [@modules_names_list] )
118 Returns a reference to the CPANPLUS module tree.
120 If you give it any arguments, they will be treated as module names
121 and C<module_tree> will try to look up these module names and
122 return the corresponding module objects instead.
124 See L<CPANPLUS::Module> for the operations you can perform on a
131 my $modtree = $self->_module_tree;
135 for my $name ( grep { defined } @_) {
137 ### From John Malmberg: This is failing on VMS
138 ### because ODS-2 does not retain the case of
139 ### filenames that are created.
140 ### The problem is the filename is being converted
141 ### to a module name and then looked up in the
144 ### As a fix, we do a search on VMS instead --
145 ### more cpu cycles, but it gets around the case
151 allow => [qr/^$name$/i],
156 push @rv, $modobj || '';
158 return @rv == 1 ? $rv[0] : @rv;
166 =head2 $href = $cb->author_tree( [@author_names_list] )
168 Returns a reference to the CPANPLUS author tree.
170 If you give it any arguments, they will be treated as author names
171 and C<author_tree> will try to look up these author names and
172 return the corresponding author objects instead.
174 See L<CPANPLUS::Module::Author> for the operations you can perform on
181 my $authtree = $self->_author_tree;
186 push @rv, $authtree->{$name} || '';
188 return @rv == 1 ? $rv[0] : @rv;
196 =head2 $conf = $cb->configure_object;
198 Returns a copy of the C<CPANPLUS::Configure> object.
200 See L<CPANPLUS::Configure> for operations you can perform on a
205 sub configure_object { return shift->_conf() };
207 =head2 $su = $cb->selfupdate_object;
209 Returns a copy of the C<CPANPLUS::Selfupdate> object.
211 See the L<CPANPLUS::Selfupdate> manpage for the operations
212 you can perform on the selfupdate object.
216 sub selfupdate_object { return shift->_selfupdate() };
220 =head2 @mods = $cb->search( type => TYPE, allow => AREF, [data => AREF, verbose => BOOL] )
222 C<search> enables you to search for either module or author objects,
223 based on their data. The C<type> you can specify is any of the
224 accessors specified in C<CPANPLUS::Module::Author> or
225 C<CPANPLUS::Module>. C<search> will determine by the C<type> you
226 specified whether to search by author object or module object.
228 You have to specify an array reference of regular expressions or
229 strings to match against. The rules used for this array ref are the
230 same as in C<Params::Check>, so read that manpage for details.
232 The search is an C<or> search, meaning that if C<any> of the criteria
233 match, the search is considered to be successful.
235 You can specify the result of a previous search as C<data> to limit
236 the new search to these module or author objects, rather than the
237 entire module or author tree. This is how you do C<and> searches.
239 Returns a list of module or author objects on success and false
242 See L<CPANPLUS::Module> for the operations you can perform on a
244 See L<CPANPLUS::Module::Author> for the operations you can perform on
251 my $conf = $self->configure_object;
256 local $Params::Check::NO_DUPLICATES = 0;
257 local $Params::Check::ALLOW_UNKNOWN = 1;
260 type => { required => 1, allow => [CPANPLUS::Module->accessors(),
261 CPANPLUS::Module::Author->accessors()], store => \$type },
262 allow => { required => 1, default => [ ], strict_type => 1 },
265 check( $tmpl, \%hash )
268 ### figure out whether it was an author or a module search
269 ### when ambiguous, it'll be an author search.
271 if( grep { $type eq $_ } CPANPLUS::Module::Author->accessors() ) {
272 $aref = $self->_search_author_tree( %$args );
274 $aref = $self->_search_module_tree( %$args );
277 return @$aref if $aref;
283 =head2 $backend_rv = $cb->fetch( modules => \@mods )
285 Fetches a list of modules. C<@mods> can be a list of distribution
286 names, module names or module objects--basically anything that
287 L<parse_module> can understand.
289 See the equivalent method in C<CPANPLUS::Module> for details on
290 other options you can pass.
292 Since this is a multi-module method call, the return value is
293 implemented as a C<CPANPLUS::Backend::RV> object. Please consult
294 that module's documentation on how to interpret the return value.
296 =head2 $backend_rv = $cb->extract( modules => \@mods )
298 Extracts a list of modules. C<@mods> can be a list of distribution
299 names, module names or module objects--basically anything that
300 L<parse_module> can understand.
302 See the equivalent method in C<CPANPLUS::Module> for details on
303 other options you can pass.
305 Since this is a multi-module method call, the return value is
306 implemented as a C<CPANPLUS::Backend::RV> object. Please consult
307 that module's documentation on how to interpret the return value.
309 =head2 $backend_rv = $cb->install( modules => \@mods )
311 Installs a list of modules. C<@mods> can be a list of distribution
312 names, module names or module objects--basically anything that
313 L<parse_module> can understand.
315 See the equivalent method in C<CPANPLUS::Module> for details on
316 other options you can pass.
318 Since this is a multi-module method call, the return value is
319 implemented as a C<CPANPLUS::Backend::RV> object. Please consult
320 that module's documentation on how to interpret the return value.
322 =head2 $backend_rv = $cb->readme( modules => \@mods )
324 Fetches the readme for a list of modules. C<@mods> can be a list of
325 distribution names, module names or module objects--basically
326 anything that L<parse_module> can understand.
328 See the equivalent method in C<CPANPLUS::Module> for details on
329 other options you can pass.
331 Since this is a multi-module method call, the return value is
332 implemented as a C<CPANPLUS::Backend::RV> object. Please consult
333 that module's documentation on how to interpret the return value.
335 =head2 $backend_rv = $cb->files( modules => \@mods )
337 Returns a list of files used by these modules if they are installed.
338 C<@mods> can be a list of distribution names, module names or module
339 objects--basically anything that L<parse_module> can understand.
341 See the equivalent method in C<CPANPLUS::Module> for details on
342 other options you can pass.
344 Since this is a multi-module method call, the return value is
345 implemented as a C<CPANPLUS::Backend::RV> object. Please consult
346 that module's documentation on how to interpret the return value.
348 =head2 $backend_rv = $cb->distributions( modules => \@mods )
350 Returns a list of module objects representing all releases for this
352 C<@mods> can be a list of distribution names, module names or module
353 objects, basically anything that L<parse_module> can understand.
355 See the equivalent method in C<CPANPLUS::Module> for details on
356 other options you can pass.
358 Since this is a multi-module method call, the return value is
359 implemented as a C<CPANPLUS::Backend::RV> object. Please consult
360 that module's documentation on how to interpret the return value.
364 ### XXX add direcotry_tree, packlist etc? or maybe remove files? ###
365 for my $func (qw[fetch extract install readme files distributions]) {
370 my $conf = $self->configure_object;
375 local $Params::Check::NO_DUPLICATES = 1;
376 local $Params::Check::ALLOW_UNKNOWN = 1;
379 modules => { default => [], strict_type => 1,
380 required => 1, store => \$mods },
383 check( $tmpl, \%hash );
386 ### make them all into module objects ###
387 my %mods = map { $_ => $self->parse_module(module => $_) || '' } @$mods;
390 while( my($name,$obj) = each %mods ) {
391 $href->{$name} = IS_MODOBJ->( mod => $obj )
392 ? $obj->$func( %$args )
395 $flag++ unless $href->{$name};
398 return CPANPLUS::Backend::RV->new(
409 =head2 $mod_obj = $cb->parse_module( module => $modname|$distname|$modobj|URI|PATH )
411 C<parse_module> tries to find a C<CPANPLUS::Module> object that
412 matches your query. Here's a list of examples you could give to
417 =item Text::Bastardize
419 =item Text-Bastardize
421 =item Text-Bastardize-1.06
423 =item AYRNIEU/Text-Bastardize
425 =item AYRNIEU/Text-Bastardize-1.06
427 =item AYRNIEU/Text-Bastardize-1.06.tar.gz
429 =item http://example.com/Text-Bastardize-1.06.tar.gz
431 =item file:///tmp/Text-Bastardize-1.06.tar.gz
433 =item /tmp/Text-Bastardize-1.06
435 =item ./Text-Bastardize-1.06
441 These items would all come up with a C<CPANPLUS::Module> object for
442 C<Text::Bastardize>. The ones marked explicitly as being version 1.06
443 would give back a C<CPANPLUS::Module> object of that version.
444 Even if the version on CPAN is currently higher.
446 The last three are examples of PATH resolution. In the first, we supply
447 an absolute path to the unwrapped distribution. In the second the
448 distribution is relative to the current working directory.
449 In the third, we will use the current working directory.
451 If C<parse_module> is unable to actually find the module you are looking
452 for in its module tree, but you supplied it with an author, module
453 and version part in a distribution name or URI, it will create a fake
454 C<CPANPLUS::Module> object for you, that you can use just like the
457 See L<CPANPLUS::Module> for the operations you can perform on a
460 If even this fancy guessing doesn't enable C<parse_module> to create
461 a fake module object for you to use, it will warn about an error and
468 my $conf = $self->configure_object;
473 module => { required => 1, store => \$mod },
476 my $args = check( $tmpl, \%hash ) or return;
478 return $mod if IS_MODOBJ->( module => $mod );
480 ### ok, so it's not a module object, but a ref nonetheless?
481 ### what are you smoking?
483 error(loc("Can not parse module string from reference '%1'", $mod ));
487 ### check only for allowed characters in a module name
488 unless( $mod =~ /[^\w:]/ ) {
490 ### perhaps we can find it in the module tree?
491 my $maybe = $self->module_tree($mod);
492 return $maybe if IS_MODOBJ->( module => $maybe );
495 ### Special case arbitary file paths such as '.' etc.
496 if (-d File::Spec->rel2abs($mod) ) {
497 my $dir = File::Spec->rel2abs($mod);
498 my $parent = File::Spec->rel2abs( File::Spec->catdir( $dir, '..' ) );
500 my $dist = $mod = File::Basename::basename($dir);
501 $dist .= '-0' unless $dist =~ /\-[0-9._]+$/;
502 $dist .= '.tar.gz' unless $dist =~ /\.[A-Za-z]+$/;
504 my $modobj = CPANPLUS::Module::Fake->new(
509 author => CPANPLUS::Module::Author::Fake->new
512 ### better guess for the version
513 $modobj->version( $modobj->package_version )
514 if defined $modobj->package_version;
516 ### better guess at module name, if possible
517 if ( my $pkgname = $modobj->package_name ) {
518 $pkgname =~ s/-/::/g;
520 ### no sense replacing it unless we changed something
521 $modobj->module( $pkgname )
522 if ($pkgname ne $modobj->package_name) || $pkgname !~ /-/;
525 $modobj->status->fetch( $parent );
526 $modobj->status->extract( $dir );
527 $modobj->get_installer_type;
531 ### ok, so it looks like a distribution then?
532 my @parts = split '/', $mod;
533 my $dist = pop @parts;
536 if( $mod =~ m|\w+://.+| ) {
537 my $modobj = CPANPLUS::Module::Fake->new(
541 path => File::Spec::Unix->catdir(
542 $conf->_get_mirror('base'),
543 UNKNOWN_DL_LOCATION ),
544 author => CPANPLUS::Module::Author::Fake->new
547 ### set the fetch_from accessor so we know to by pass the
549 $modobj->status->_fetch_from( $mod );
551 ### better guess for the version
552 $modobj->version( $modobj->package_version )
553 if defined $modobj->package_version;
555 ### better guess at module name, if possible
556 if ( my $pkgname = $modobj->package_name ) {
557 $pkgname =~ s/-/::/g;
559 ### no sense replacing it unless we changed something
560 $modobj->module( $pkgname )
561 if ($pkgname ne $modobj->package_name) || $pkgname !~ /-/;
567 ### perhaps we can find it's a third party module?
568 { my $modobj = CPANPLUS::Module::Fake->new(
572 path => File::Spec::Unix->catdir(
573 $conf->_get_mirror('base'),
574 UNKNOWN_DL_LOCATION ),
575 author => CPANPLUS::Module::Author::Fake->new
577 if( $modobj->is_third_party ) {
578 my $info = $modobj->third_party_information;
580 $modobj->author->author( $info->{author} );
581 $modobj->author->email( $info->{author_url} );
582 $modobj->description( $info->{url} );
589 error( loc("%1 is not a proper distribution name!", $mod) );
593 ### there's wonky uris out there, like this:
594 ### E/EY/EYCK/Net/Lite/Net-Lite-FTP-0.091
595 ### compensate for that
597 ### you probably have an A/AB/ABC/....../Dist.tgz type uri
598 if( (defined $parts[0] and length $parts[0] == 1) and
599 (defined $parts[1] and length $parts[1] == 2) and
600 $parts[2] =~ /^$parts[0]/i and $parts[2] =~ /^$parts[1]/i
602 splice @parts, 0, 2; # remove the first 2 entries from the list
603 $author = shift @parts; # this is the actual author name then
605 ### we''ll assume a ABC/..../Dist.tgz
607 $author = shift @parts || '';
610 my($pkg, $version, $ext, $full) =
611 $self->_split_package_string( package => $dist );
613 ### translate a distribution into a module name ###
615 $guess =~ s/-/::/g if $guess;
617 my $maybe = $self->module_tree( $guess );
618 if( IS_MODOBJ->( module => $maybe ) ) {
620 ### maybe you asked for a package instead
621 if ( $maybe->package eq $mod ) {
624 ### perhaps an outdated version instead?
625 } elsif ( $version ) {
626 my $auth_obj; my $path;
628 ### did you give us an author part? ###
630 $auth_obj = CPANPLUS::Module::Author::Fake->new(
632 cpanid => uc $author,
633 author => uc $author,
635 $path = File::Spec::Unix->catdir(
636 $conf->_get_mirror('base'),
637 substr(uc $author, 0, 1),
638 substr(uc $author, 0, 2),
640 @parts, #possible sub dirs
643 $auth_obj = $maybe->author;
644 $path = $maybe->path;
647 if( $maybe->package_name eq $pkg ) {
649 my $modobj = CPANPLUS::Module::Fake->new(
650 module => $maybe->module,
652 ### no extension? use the extension the original package
656 : $full .'.'. $maybe->package_extension
664 ### you asked for a specific version?
665 ### assume our $maybe is the one you wanted,
666 ### and fix up the version..
669 my $modobj = $maybe->clone;
670 $modobj->version( $version );
672 $maybe->package_name .'-'.
674 $maybe->package_extension
677 ### you wanted a specific author, but it's not the one
678 ### from the module tree? we'll fix it up
679 if( $author and $author ne $modobj->author->cpanid ) {
680 $modobj->author( $auth_obj );
681 $modobj->path( $path );
687 ### you didn't care about a version, so just return the object then
688 } elsif ( !$version ) {
692 ### ok, so we can't find it, and it's not an outdated dist either
693 ### perhaps we can fake one based on the author name and so on
694 } elsif ( $author and $version ) {
696 ### be extra friendly and pad the .tar.gz suffix where needed
697 ### it's just a guess of course, but most dists are .tar.gz
698 $dist .= '.tar.gz' unless $dist =~ /\.[A-Za-z]+$/;
700 ### XXX duplication from above for generating author obj + path...
701 my $modobj = CPANPLUS::Module::Fake->new(
705 author => CPANPLUS::Module::Author::Fake->new(
706 author => uc $author,
707 cpanid => uc $author,
710 path => File::Spec::Unix->catdir(
711 $conf->_get_mirror('base'),
712 substr(uc $author, 0, 1),
713 substr(uc $author, 0, 2),
715 @parts, #possible subdirs
722 ### face it, we have /no/ idea what he or she wants...
723 ### let's start putting the blame somewhere
727 error( loc( "'%1' does not contain an author part", $mod ) );
730 error( loc( "Cannot find '%1' in the module tree", $mod ) );
738 =head2 $bool = $cb->reload_indices( [update_source => BOOL, verbose => BOOL] );
740 This method reloads the source files.
742 If C<update_source> is set to true, this will fetch new source files
743 from your CPAN mirror. Otherwise, C<reload_indices> will do its
744 usual cache checking and only update them if they are out of date.
746 By default, C<update_source> will be false.
748 The verbose setting defaults to what you have specified in your
751 Returns true on success and false on failure.
758 my $conf = $self->configure_object;
761 update_source => { default => 0, allow => [qr/^\d$/] },
762 verbose => { default => $conf->get_conf('verbose') },
765 my $args = check( $tmpl, \%hash ) or return;
767 ### make a call to the internal _module_tree, so it triggers cache
769 my $uptodate = $self->_check_trees( %$args );
772 return 1 if $self->_build_trees(
773 uptodate => $uptodate,
775 verbose => $conf->get_conf('verbose'),
778 error( loc( "Error rebuilding source trees!" ) );
785 =head2 $bool = $cb->flush(CACHE_NAME)
787 This method allows flushing of caches.
788 There are several things which can be flushed:
794 The return status of methods which have been attempted, such as
795 different ways of fetching files. It is recommended that automatic
796 flushing be used instead.
800 The return status of URIs which have been attempted, such as
801 different hosts of fetching files. It is recommended that automatic
802 flushing be used instead.
806 Information about modules such as prerequisites and whether
807 installation succeeded, failed, or was not attempted.
811 This resets PERL5LIB, which is changed to ensure that while installing
812 modules they are in our @INC.
816 This resets the cache of modules we've attempted to load, but failed.
817 This enables you to load them again after a failed load, if they
818 somehow have become available.
822 Flush all of the aforementioned caches.
826 Returns true on success and false on failure.
832 my $type = shift or return;
835 methods => [ qw( methods load ) ],
836 hosts => [ qw( hosts ) ],
837 modules => [ qw( modules lib) ],
838 lib => [ qw( lib ) ],
839 load => [ qw( load ) ],
840 all => [ qw( hosts lib modules methods load ) ],
843 my $aref = $cache->{$type}
845 error( loc("No such cache '%1'", $type) ),
849 return $self->_flush( list => $aref );
854 =head2 @mods = $cb->installed()
856 Returns a list of module objects of all your installed modules.
857 If an error occurs, it will return false.
859 See L<CPANPLUS::Module> for the operations you can perform on a
866 my $aref = $self->_all_installed;
868 return @$aref if $aref;
874 =head2 $bool = $cb->local_mirror([path => '/dir/to/save/to', index_files => BOOL, force => BOOL, verbose => BOOL] )
876 Creates a local mirror of CPAN, of only the most recent sources in a
877 location you specify. If you set this location equal to a custom host
878 in your C<CPANPLUS::Config> you can use your local mirror to install
881 It takes the following arguments:
887 The location where to create the local mirror.
891 Enable/disable fetching of index files. You can disable fetching of the
892 index files if you don't plan to use the local mirror as your primary
893 site, or if you'd like up-to-date index files be fetched from elsewhere.
899 Forces refetching of packages, even if they are there already.
901 Defaults to whatever setting you have in your C<CPANPLUS::Config>.
905 Prints more messages about what its doing.
907 Defaults to whatever setting you have in your C<CPANPLUS::Config>.
911 Returns true on success and false on error.
917 my $conf = $self->configure_object;
920 my($path, $index, $force, $verbose);
922 path => { default => $conf->get_conf('base'),
924 index_files => { default => 1, store => \$index },
925 force => { default => $conf->get_conf('force'),
927 verbose => { default => $conf->get_conf('verbose'),
928 store => \$verbose },
931 check( $tmpl, \%hash ) or return;
934 $self->_mkdir( dir => $path )
935 or( error( loc( "Could not create '%1', giving up", $path ) ),
939 error( loc( "Could not write to '%1', giving up", $path ) );
945 for my $auth ( sort { $a->cpanid cmp $b->cpanid }
946 values %{$self->author_tree}
951 for my $mod ( $auth->modules ) {
952 my $fetchdir = File::Spec->catdir( $path, $mod->path );
957 fetchdir => $fetchdir,
960 ### only do this the for the first module ###
962 $mod->_get_checksums_file(
965 error( loc( "Could not fetch %1 file, " .
966 "skipping author '%2'",
967 CHECKSUMS, $auth->cpanid ) ),
973 or( error( loc( "Could not fetch '%1'", $mod->module ) ),
980 for my $name (qw[auth dslip mod]) {
981 $self->_update_source(
985 ) or ( $flag++, next );
994 =head2 $file = $cb->autobundle([path => OUTPUT_PATH, force => BOOL, verbose => BOOL])
996 Writes out a snapshot of your current installation in C<CPAN> bundle
997 style. This can then be used to install the same modules for a
998 different or on a different machine by issuing the following commands:
1000 ### using the default shell:
1001 CPAN Terminal> i file://path/to/Snapshot_XXYY.pm
1004 $modobj = $cb->parse_module( module => 'file://path/to/Snapshot_XXYY.pm' );
1007 It will, by default, write to an 'autobundle' directory under your
1008 cpanplus homedirectory, but you can override that by supplying a
1011 It will return the location of the output file on success and false on
1018 my $conf = $self->configure_object;
1021 my($path,$force,$verbose);
1023 force => { default => $conf->get_conf('force'), store => \$force },
1024 verbose => { default => $conf->get_conf('verbose'), store => \$verbose },
1025 path => { default => File::Spec->catdir(
1026 $conf->get_conf('base'),
1027 $self->_perl_version( perl => $^X ),
1028 $conf->_get_build('distdir'),
1029 $conf->_get_build('autobundle') ),
1033 check($tmpl, \%hash) or return;
1035 unless( -d $path ) {
1036 $self->_mkdir( dir => $path )
1037 or( error(loc("Could not create directory '%1'", $path ) ),
1043 { ### default filename for the bundle ###
1044 my($year,$month,$day) = (localtime)[5,4,3];
1045 $year += 1900; $month++;
1049 my $prefix = $conf->_get_build('autobundle_prefix');
1050 my $format = "${prefix}_%04d_%02d_%02d_%02d";
1053 $name = sprintf( $format, $year, $month, $day, $ext);
1055 $file = File::Spec->catfile( $path, $name . '.pm' );
1057 -f $file ? ++$ext && redo BLOCK : last BLOCK;
1061 unless( $fh = FileHandle->new( ">$file" ) ) {
1062 error( loc( "Could not open '%1' for writing: %2", $file, $! ) );
1066 ### make sure we load the module tree *before* doing this, as it
1067 ### starts to chdir all over the place
1070 my $string = join "\n\n",
1074 ($_->installed_version(verbose => 0) || 'undef')
1076 $a->module cmp $b->module
1079 my $now = scalar localtime;
1080 my $head = '=head1';
1081 my $pkg = __PACKAGE__;
1082 my $version = $self->VERSION;
1083 my $perl_v = join '', `$^X -V`;
1096 $name - Snapshot of your installation at $now
1100 perl -MCPANPLUS -e "install file://full/path/to/$name"
1112 This bundle has been generated autotomatically by
1122 =head2 $bool = $cb->save_state
1124 Explicit command to save memory state to disk. This can be used to save
1125 information to disk about where a module was extracted, the result of
1126 C<make test>, etc. This will then be re-loaded into memory when a new
1129 The capability of saving state to disk depends on the source engine
1130 being used (See C<CPANPLUS::Config> for the option to choose your
1131 source engine). The default storage engine supports this option.
1133 Most users will not need this command, but it can handy for automated
1134 systems like setting up CPAN smoke testers.
1136 The method will return true if it managed to save the state to disk,
1137 or false if it did not.
1143 return $self->_save_state( @_ );
1147 ### XXX these wrappers are not individually tested! only the underlying
1148 ### code through source.t and indirectly trought he CustomSource plugin.
1151 =head1 CUSTOM MODULE SOURCES
1153 Besides the sources as provided by the general C<CPAN> mirrors, it's
1154 possible to add your own sources list to your C<CPANPLUS> index.
1156 The methodology behind this works much like C<Debian's apt-sources>.
1158 The methods below show you how to make use of this functionality. Also
1159 note that most of these methods are available through the default shell
1160 plugin command C</cs>, making them available as shortcuts through the
1161 shell and via the commandline.
1163 =head2 %files = $cb->list_custom_sources
1165 Returns a mapping of registered custom sources and their local indices
1168 /full/path/to/local/index => http://remote/source
1170 Note that any file starting with an C<#> is being ignored.
1174 sub list_custom_sources {
1175 return shift->__list_custom_module_sources( @_ );
1178 =head2 $local_index = $cb->add_custom_source( uri => URI, [verbose => BOOL] );
1180 Adds an C<URI> to your own sources list and mirrors its index. See the
1181 documentation on C<< $cb->update_custom_source >> on how this is done.
1183 Returns the full path to the local index on success, or false on failure.
1185 Note that when adding a new C<URI>, the change to the in-memory tree is
1186 not saved until you rebuild or save the tree to disk again. You can do
1187 this using the C<< $cb->reload_indices >> method.
1191 sub add_custom_source {
1192 return shift->_add_custom_module_source( @_ );
1195 =head2 $local_index = $cb->remove_custom_source( uri => URI, [verbose => BOOL] );
1197 Removes an C<URI> from your own sources list and removes its index.
1199 To find out what C<URI>s you have as part of your own sources list, use
1200 the C<< $cb->list_custom_sources >> method.
1202 Returns the full path to the deleted local index file on success, or false
1207 ### XXX do clever dispatching based on arg number?
1208 sub remove_custom_source {
1209 return shift->_remove_custom_module_source( @_ );
1212 =head2 $bool = $cb->update_custom_source( [remote => URI] );
1214 Updates the indexes for all your custom sources. It does this by fetching
1215 a file called C<packages.txt> in the root of the custom sources's C<URI>.
1216 If you provide the C<remote> argument, it will only update the index for
1217 that specific C<URI>.
1219 Here's an example of how custom sources would resolve into index files:
1221 file:///path/to/sources => file:///path/to/sources/packages.txt
1222 http://example.com/sources => http://example.com/sources/packages.txt
1223 ftp://example.com/sources => ftp://example.com/sources/packages.txt
1225 The file C<packages.txt> simply holds a list of packages that can be found
1226 under the root of the C<URI>. This file can be automatically generated for
1227 you when the remote source is a C<file:// URI>. For C<http://>, C<ftp://>,
1228 and similar, the administrator of that repository should run the method
1229 C<< $cb->write_custom_source_index >> on the repository to allow remote
1232 For details, see the C<< $cb->write_custom_source_index >> method below.
1234 All packages that are added via this mechanism will be attributed to the
1235 author with C<CPANID> C<LOCAL>. You can use this id to search for all
1240 sub update_custom_source {
1243 ### if it mentions /remote/, the request is to update a single uri,
1244 ### not all the ones we have, so dispatch appropriately
1245 my $rv = grep( /remote/i, @_)
1246 ? $self->__update_custom_module_source( @_ )
1247 : $self->__update_custom_module_sources( @_ );
1252 =head2 $file = $cb->write_custom_source_index( path => /path/to/package/root, [to => /path/to/index/file, verbose => BOOL] );
1254 Writes the index for a custom repository root. Most users will not have to
1255 worry about this, but administrators of a repository will need to make sure
1256 their indexes are up to date.
1258 The index will be written to a file called C<packages.txt> in your repository
1259 root, which you can specify with the C<path> argument. You can override this
1260 location by specifying the C<to> argument, but in normal operation, that should
1263 Once the index file is written, users can then add the C<URI> pointing to
1264 the repository to their custom list of sources and start using it right away. See the C<< $cb->add_custom_source >> method for user details.
1268 sub write_custom_source_index {
1269 return shift->__write_custom_module_index( @_ );
1278 Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>.
1282 This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
1286 The CPAN++ interface (of which this module is a part of) is copyright (c)
1287 2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved.
1289 This library is free software; you may redistribute and/or modify it
1290 under the same terms as Perl itself.
1294 L<CPANPLUS::Configure>, L<CPANPLUS::Module>, L<CPANPLUS::Module::Author>,
1295 L<CPANPLUS::Selfupdate>
1300 # c-indentation-style: bsd
1302 # indent-tabs-mode: nil
1304 # vim: expandtab shiftwidth=4:
1309 sub dist { # not sure about this one -- probably already done
1311 sub reports { # in Module.pm, wrapper here