home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / perl / 5.10.0 / CPANPLUS / Backend.pm next >
Encoding:
Perl POD Document  |  2009-06-26  |  35.6 KB  |  1,228 lines

  1. package CPANPLUS::Backend;
  2.  
  3. use strict;
  4.  
  5.  
  6. use CPANPLUS::Error;
  7. use CPANPLUS::Configure;
  8. use CPANPLUS::Internals;
  9. use CPANPLUS::Internals::Constants;
  10. use CPANPLUS::Module;
  11. use CPANPLUS::Module::Author;
  12. use CPANPLUS::Backend::RV;
  13.  
  14. use FileHandle;
  15. use File::Spec                  ();
  16. use File::Spec::Unix            ();
  17. use Params::Check               qw[check];
  18. use Locale::Maketext::Simple    Class => 'CPANPLUS', Style => 'gettext';
  19.  
  20. $Params::Check::VERBOSE = 1;
  21.  
  22. use vars qw[@ISA $VERSION];
  23.  
  24. @ISA     = qw[CPANPLUS::Internals];
  25. $VERSION = $CPANPLUS::Internals::VERSION;
  26.  
  27. ### mark that we're running under CPANPLUS to spawned processes
  28. $ENV{'PERL5_CPANPLUS_IS_RUNNING'} = $$;
  29.  
  30. ### XXX version.pm MAY format this version, if it's in use... :(
  31. ### so for consistency, just call ->VERSION ourselves as well.
  32. $ENV{'PERL5_CPANPLUS_IS_VERSION'} = __PACKAGE__->VERSION;
  33.  
  34. =pod
  35.  
  36. =head1 NAME
  37.  
  38. CPANPLUS::Backend
  39.  
  40. =head1 SYNOPSIS
  41.  
  42.     my $cb      = CPANPLUS::Backend->new;
  43.     my $conf    = $cb->configure_object;
  44.  
  45.     my $author  = $cb->author_tree('KANE');
  46.     my $mod     = $cb->module_tree('Some::Module');
  47.     my $mod     = $cb->parse_module( module => 'Some::Module' );
  48.  
  49.     my @objs    = $cb->search(  type    => TYPE,
  50.                                 allow   => [...] );
  51.  
  52.     $cb->flush('all');
  53.     $cb->reload_indices;
  54.     $cb->local_mirror;
  55.  
  56.  
  57. =head1 DESCRIPTION
  58.  
  59. This module provides the programmer's interface to the C<CPANPLUS>
  60. libraries.
  61.  
  62. =head1 ENVIRONMENT
  63.  
  64. When C<CPANPLUS::Backend> is loaded, which is necessary for just
  65. about every <CPANPLUS> operation, the environment variable
  66. C<PERL5_CPANPLUS_IS_RUNNING> is set to the current process id.
  67.  
  68. Additionally, the environment variable C<PERL5_CPANPLUS_IS_VERSION> 
  69. will be set to the version of C<CPANPLUS::Backend>.
  70.  
  71. This information might be useful somehow to spawned processes.
  72.  
  73. =head1 METHODS
  74.  
  75. =head2 $cb = CPANPLUS::Backend->new( [CONFIGURE_OBJ] )
  76.  
  77. This method returns a new C<CPANPLUS::Backend> object.
  78. This also initialises the config corresponding to this object.
  79. You have two choices in this:
  80.  
  81. =over 4
  82.  
  83. =item Provide a valid C<CPANPLUS::Configure> object
  84.  
  85. This will be used verbatim.
  86.  
  87. =item No arguments
  88.  
  89. Your default config will be loaded and used.
  90.  
  91. =back
  92.  
  93. New will return a C<CPANPLUS::Backend> object on success and die on
  94. failure.
  95.  
  96. =cut
  97.  
  98. sub new {
  99.     my $class   = shift;
  100.     my $conf;
  101.  
  102.     if( $_[0] && IS_CONFOBJ->( conf => $_[0] ) ) {
  103.         $conf = shift;
  104.     } else {
  105.         $conf = CPANPLUS::Configure->new() or return;
  106.     }
  107.  
  108.     my $self = $class->SUPER::_init( _conf => $conf );
  109.  
  110.     return $self;
  111. }
  112.  
  113. =pod
  114.  
  115. =head2 $href = $cb->module_tree( [@modules_names_list] )
  116.  
  117. Returns a reference to the CPANPLUS module tree.
  118.  
  119. If you give it any arguments, they will be treated as module names
  120. and C<module_tree> will try to look up these module names and
  121. return the corresponding module objects instead.
  122.  
  123. See L<CPANPLUS::Module> for the operations you can perform on a
  124. module object.
  125.  
  126. =cut
  127.  
  128. sub module_tree {
  129.     my $self    = shift;
  130.     my $modtree = $self->_module_tree;
  131.  
  132.     if( @_ ) {
  133.         my @rv;
  134.         for my $name ( grep { defined } @_) {
  135.  
  136.             ### From John Malmberg: This is failing on VMS 
  137.             ### because ODS-2 does not retain the case of 
  138.             ### filenames that are created.
  139.             ### The problem is the filename is being converted 
  140.             ### to a module name and then looked up in the 
  141.             ### %$modtree hash.
  142.             ### 
  143.             ### As a fix, we do a search on VMS instead --
  144.             ### more cpu cycles, but it gets around the case
  145.             ### problem --kane
  146.             my ($modobj) = do {
  147.                 ON_VMS
  148.                     ? $self->search(
  149.                           type    => 'module',
  150.                           allow   => [qr/^$name$/i],
  151.                       )
  152.                     : $modtree->{$name}
  153.             };
  154.             
  155.             push @rv, $modobj || '';
  156.         }
  157.         return @rv == 1 ? $rv[0] : @rv;
  158.     } else {
  159.         return $modtree;
  160.     }
  161. }
  162.  
  163. =pod
  164.  
  165. =head2 $href = $cb->author_tree( [@author_names_list] )
  166.  
  167. Returns a reference to the CPANPLUS author tree.
  168.  
  169. If you give it any arguments, they will be treated as author names
  170. and C<author_tree> will try to look up these author names and
  171. return the corresponding author objects instead.
  172.  
  173. See L<CPANPLUS::Module::Author> for the operations you can perform on
  174. an author object.
  175.  
  176. =cut
  177.  
  178. sub author_tree {
  179.     my $self        = shift;
  180.     my $authtree    = $self->_author_tree;
  181.  
  182.     if( @_ ) {
  183.         my @rv;
  184.         for my $name (@_) {
  185.             push @rv, $authtree->{$name} || '';
  186.         }
  187.         return @rv == 1 ? $rv[0] : @rv;
  188.     } else {
  189.         return $authtree;
  190.     }
  191. }
  192.  
  193. =pod
  194.  
  195. =head2 $conf = $cb->configure_object;
  196.  
  197. Returns a copy of the C<CPANPLUS::Configure> object.
  198.  
  199. See L<CPANPLUS::Configure> for operations you can perform on a
  200. configure object.
  201.  
  202. =cut
  203.  
  204. sub configure_object { return shift->_conf() };
  205.  
  206. =head2 $su = $cb->selfupdate_object;
  207.  
  208. Returns a copy of the C<CPANPLUS::Selfupdate> object.
  209.  
  210. See the L<CPANPLUS::Selfupdate> manpage for the operations
  211. you can perform on the selfupdate object.
  212.  
  213. =cut
  214.  
  215. sub selfupdate_object { return shift->_selfupdate() };
  216.  
  217. =pod
  218.  
  219. =head2 @mods = $cb->search( type => TYPE, allow => AREF, [data => AREF, verbose => BOOL] )
  220.  
  221. C<search> enables you to search for either module or author objects,
  222. based on their data. The C<type> you can specify is any of the
  223. accessors specified in C<CPANPLUS::Module::Author> or
  224. C<CPANPLUS::Module>. C<search> will determine by the C<type> you
  225. specified whether to search by author object or module object.
  226.  
  227. You have to specify an array reference of regular expressions or
  228. strings to match against. The rules used for this array ref are the
  229. same as in C<Params::Check>, so read that manpage for details.
  230.  
  231. The search is an C<or> search, meaning that if C<any> of the criteria
  232. match, the search is considered to be successful.
  233.  
  234. You can specify the result of a previous search as C<data> to limit
  235. the new search to these module or author objects, rather than the
  236. entire module or author tree.  This is how you do C<and> searches.
  237.  
  238. Returns a list of module or author objects on success and false
  239. on failure.
  240.  
  241. See L<CPANPLUS::Module> for the operations you can perform on a
  242. module object.
  243. See L<CPANPLUS::Module::Author> for the operations you can perform on
  244. an author object.
  245.  
  246. =cut
  247.  
  248. sub search {
  249.     my $self = shift;
  250.     my $conf = $self->configure_object;
  251.     my %hash = @_;
  252.  
  253.     my ($type);
  254.     my $args = do {
  255.         local $Params::Check::NO_DUPLICATES = 0;
  256.         local $Params::Check::ALLOW_UNKNOWN = 1;
  257.  
  258.         my $tmpl = {
  259.             type    => { required => 1, allow => [CPANPLUS::Module->accessors(),
  260.                             CPANPLUS::Module::Author->accessors()], store => \$type },
  261.             allow   => { required => 1, default => [ ], strict_type => 1 },
  262.         };
  263.  
  264.         check( $tmpl, \%hash )
  265.     } or return;
  266.  
  267.     ### figure out whether it was an author or a module search
  268.     ### when ambiguous, it'll be an author search.
  269.     my $aref;
  270.     if( grep { $type eq $_ } CPANPLUS::Module::Author->accessors() ) {
  271.         $aref = $self->_search_author_tree( %$args );
  272.     } else {
  273.         $aref = $self->_search_module_tree( %$args );
  274.     }
  275.  
  276.     return @$aref if $aref;
  277.     return;
  278. }
  279.  
  280. =pod
  281.  
  282. =head2 $backend_rv = $cb->fetch( modules => \@mods )
  283.  
  284. Fetches a list of modules. C<@mods> can be a list of distribution
  285. names, module names or module objects--basically anything that
  286. L<parse_module> can understand.
  287.  
  288. See the equivalent method in C<CPANPLUS::Module> for details on
  289. other options you can pass.
  290.  
  291. Since this is a multi-module method call, the return value is
  292. implemented as a C<CPANPLUS::Backend::RV> object. Please consult
  293. that module's documentation on how to interpret the return value.
  294.  
  295. =head2 $backend_rv = $cb->extract( modules => \@mods )
  296.  
  297. Extracts a list of modules. C<@mods> can be a list of distribution
  298. names, module names or module objects--basically anything that
  299. L<parse_module> can understand.
  300.  
  301. See the equivalent method in C<CPANPLUS::Module> for details on
  302. other options you can pass.
  303.  
  304. Since this is a multi-module method call, the return value is
  305. implemented as a C<CPANPLUS::Backend::RV> object. Please consult
  306. that module's documentation on how to interpret the return value.
  307.  
  308. =head2 $backend_rv = $cb->install( modules => \@mods )
  309.  
  310. Installs a list of modules. C<@mods> can be a list of distribution
  311. names, module names or module objects--basically anything that
  312. L<parse_module> can understand.
  313.  
  314. See the equivalent method in C<CPANPLUS::Module> for details on
  315. other options you can pass.
  316.  
  317. Since this is a multi-module method call, the return value is
  318. implemented as a C<CPANPLUS::Backend::RV> object. Please consult
  319. that module's documentation on how to interpret the return value.
  320.  
  321. =head2 $backend_rv = $cb->readme( modules => \@mods )
  322.  
  323. Fetches the readme for a list of modules. C<@mods> can be a list of
  324. distribution names, module names or module objects--basically
  325. anything that L<parse_module> can understand.
  326.  
  327. See the equivalent method in C<CPANPLUS::Module> for details on
  328. other options you can pass.
  329.  
  330. Since this is a multi-module method call, the return value is
  331. implemented as a C<CPANPLUS::Backend::RV> object. Please consult
  332. that module's documentation on how to interpret the return value.
  333.  
  334. =head2 $backend_rv = $cb->files( modules => \@mods )
  335.  
  336. Returns a list of files used by these modules if they are installed.
  337. C<@mods> can be a list of distribution names, module names or module
  338. objects--basically anything that L<parse_module> can understand.
  339.  
  340. See the equivalent method in C<CPANPLUS::Module> for details on
  341. other options you can pass.
  342.  
  343. Since this is a multi-module method call, the return value is
  344. implemented as a C<CPANPLUS::Backend::RV> object. Please consult
  345. that module's documentation on how to interpret the return value.
  346.  
  347. =head2 $backend_rv = $cb->distributions( modules => \@mods )
  348.  
  349. Returns a list of module objects representing all releases for this
  350. module on success.
  351. C<@mods> can be a list of distribution names, module names or module
  352. objects, basically anything that L<parse_module> can understand.
  353.  
  354. See the equivalent method in C<CPANPLUS::Module> for details on
  355. other options you can pass.
  356.  
  357. Since this is a multi-module method call, the return value is
  358. implemented as a C<CPANPLUS::Backend::RV> object. Please consult
  359. that module's documentation on how to interpret the return value.
  360.  
  361. =cut
  362.  
  363. ### XXX add direcotry_tree, packlist etc? or maybe remove files? ###
  364. for my $func (qw[fetch extract install readme files distributions]) {
  365.     no strict 'refs';
  366.  
  367.     *$func = sub {
  368.         my $self = shift;
  369.         my $conf = $self->configure_object;
  370.         my %hash = @_;
  371.  
  372.         local $Params::Check::NO_DUPLICATES = 1;
  373.         local $Params::Check::ALLOW_UNKNOWN = 1;
  374.  
  375.         my ($mods);
  376.         my $tmpl = {
  377.             modules     => { default  => [],    strict_type => 1,
  378.                              required => 1,     store => \$mods },
  379.         };
  380.  
  381.         my $args = check( $tmpl, \%hash ) or return;
  382.  
  383.         ### make them all into module objects ###
  384.         my %mods = map {$_ => $self->parse_module(module => $_) || ''} @$mods;
  385.  
  386.         my $flag; my $href;
  387.         while( my($name,$obj) = each %mods ) {
  388.             $href->{$name} = IS_MODOBJ->( mod => $obj )
  389.                                 ? $obj->$func( %$args )
  390.                                 : undef;
  391.  
  392.             $flag++ unless $href->{$name};
  393.         }
  394.  
  395.         return CPANPLUS::Backend::RV->new(
  396.                     function    => $func,
  397.                     ok          => !$flag,
  398.                     rv          => $href,
  399.                     args        => \%hash,
  400.                 );
  401.     }
  402. }
  403.  
  404. =pod
  405.  
  406. =head2 $mod_obj = $cb->parse_module( module => $modname|$distname|$modobj|URI )
  407.  
  408. C<parse_module> tries to find a C<CPANPLUS::Module> object that
  409. matches your query. Here's a list of examples you could give to
  410. C<parse_module>;
  411.  
  412. =over 4
  413.  
  414. =item Text::Bastardize
  415.  
  416. =item Text-Bastardize
  417.  
  418. =item Text-Bastardize-1.06
  419.  
  420. =item AYRNIEU/Text-Bastardize
  421.  
  422. =item AYRNIEU/Text-Bastardize-1.06
  423.  
  424. =item AYRNIEU/Text-Bastardize-1.06.tar.gz
  425.  
  426. =item http://example.com/Text-Bastardize-1.06.tar.gz
  427.  
  428. =item file:///tmp/Text-Bastardize-1.06.tar.gz
  429.  
  430. =back
  431.  
  432. These items would all come up with a C<CPANPLUS::Module> object for
  433. C<Text::Bastardize>. The ones marked explicitly as being version 1.06
  434. would give back a C<CPANPLUS::Module> object of that version.
  435. Even if the version on CPAN is currently higher.
  436.  
  437. If C<parse_module> is unable to actually find the module you are looking
  438. for in its module tree, but you supplied it with an author, module
  439. and version part in a distribution name or URI, it will create a fake
  440. C<CPANPLUS::Module> object for you, that you can use just like the
  441. real thing.
  442.  
  443. See L<CPANPLUS::Module> for the operations you can perform on a
  444. module object.
  445.  
  446. If even this fancy guessing doesn't enable C<parse_module> to create
  447. a fake module object for you to use, it will warn about an error and
  448. return false.
  449.  
  450. =cut
  451.  
  452. sub parse_module {
  453.     my $self = shift;
  454.     my $conf = $self->configure_object;
  455.     my %hash = @_;
  456.  
  457.     my $mod;
  458.     my $tmpl = {
  459.         module  => { required => 1, store => \$mod },
  460.     };
  461.  
  462.     my $args = check( $tmpl, \%hash ) or return;
  463.  
  464.     return $mod if IS_MODOBJ->( module => $mod );
  465.  
  466.     ### ok, so it's not a module object, but a ref nonetheless?
  467.     ### what are you smoking?
  468.     if( ref $mod ) {
  469.         error(loc("Can not parse module string from reference '%1'", $mod ));
  470.         return;
  471.     }
  472.     
  473.     ### check only for allowed characters in a module name
  474.     unless( $mod =~ /[^\w:]/ ) {
  475.  
  476.         ### perhaps we can find it in the module tree?
  477.         my $maybe = $self->module_tree($mod);
  478.         return $maybe if IS_MODOBJ->( module => $maybe );
  479.     }
  480.  
  481.     ### ok, so it looks like a distribution then?
  482.     my @parts   = split '/', $mod;
  483.     my $dist    = pop @parts;
  484.  
  485.     ### ah, it's a URL
  486.     if( $mod =~ m|\w+://.+| ) {
  487.         my $modobj = CPANPLUS::Module::Fake->new(
  488.                         module  => $dist,
  489.                         version => 0,
  490.                         package => $dist,
  491.                         path    => File::Spec::Unix->catdir(
  492.                                         $conf->_get_mirror('base'),
  493.                                         UNKNOWN_DL_LOCATION ),
  494.                         author  => CPANPLUS::Module::Author::Fake->new
  495.                     );
  496.         
  497.         ### set the fetch_from accessor so we know to by pass the
  498.         ### usual mirrors
  499.         $modobj->status->_fetch_from( $mod );
  500.         
  501.         ### better guess for the version
  502.         $modobj->version( $modobj->package_version ) 
  503.             if defined $modobj->package_version;
  504.         
  505.         ### better guess at module name, if possible
  506.         if ( my $pkgname = $modobj->package_name ) {
  507.             $pkgname =~ s/-/::/g;
  508.         
  509.             ### no sense replacing it unless we changed something
  510.             $modobj->module( $pkgname ) 
  511.                 if ($pkgname ne $modobj->package_name) || $pkgname !~ /-/;
  512.         }                
  513.         
  514.         return $modobj;      
  515.     }
  516.     
  517.     ### perhaps we can find it's a third party module?
  518.     {   my $modobj = CPANPLUS::Module::Fake->new(
  519.                         module  => $mod,
  520.                         version => 0,
  521.                         package => $dist,
  522.                         path    => File::Spec::Unix->catdir(
  523.                                         $conf->_get_mirror('base'),
  524.                                         UNKNOWN_DL_LOCATION ),
  525.                         author  => CPANPLUS::Module::Author::Fake->new
  526.                     );
  527.         if( $modobj->is_third_party ) {
  528.             my $info = $modobj->third_party_information;
  529.             
  530.             $modobj->author->author( $info->{author}     );
  531.             $modobj->author->email(  $info->{author_url} );
  532.             $modobj->description(    $info->{url} );
  533.  
  534.             return $modobj;
  535.         }
  536.     }
  537.  
  538.     unless( $dist ) {
  539.         error( loc("%1 is not a proper distribution name!", $mod) );
  540.         return;
  541.     }
  542.     
  543.     ### there's wonky uris out there, like this:
  544.     ### E/EY/EYCK/Net/Lite/Net-Lite-FTP-0.091
  545.     ### compensate for that
  546.     my $author;
  547.     ### you probably have an A/AB/ABC/....../Dist.tgz type uri
  548.     if( (defined $parts[0] and length $parts[0] == 1) and 
  549.         (defined $parts[1] and length $parts[1] == 2) and
  550.         $parts[2] =~ /^$parts[0]/i and $parts[2] =~ /^$parts[1]/i
  551.     ) {   
  552.         splice @parts, 0, 2;    # remove the first 2 entries from the list
  553.         $author = shift @parts; # this is the actual author name then    
  554.  
  555.     ### we''ll assume a ABC/..../Dist.tgz
  556.     } else {
  557.         $author = shift @parts || '';
  558.     }
  559.     
  560.     my($pkg, $version, $ext) = 
  561.         $self->_split_package_string( package => $dist );
  562.     
  563.     ### translate a distribution into a module name ###
  564.     my $guess = $pkg; 
  565.     $guess =~ s/-/::/g if $guess; 
  566.  
  567.     my $maybe = $self->module_tree( $guess );
  568.     if( IS_MODOBJ->( module => $maybe ) ) {
  569.  
  570.         ### maybe you asked for a package instead
  571.         if ( $maybe->package eq $mod ) {
  572.             return $maybe;
  573.  
  574.         ### perhaps an outdated version instead?
  575.         } elsif ( $version ) {
  576.             my $auth_obj; my $path;
  577.  
  578.             ### did you give us an author part? ###
  579.             if( $author ) {
  580.                 $auth_obj   = CPANPLUS::Module::Author::Fake->new(
  581.                                     _id     => $maybe->_id,
  582.                                     cpanid  => uc $author,
  583.                                     author  => uc $author,
  584.                                 );
  585.                 $path       = File::Spec::Unix->catdir(
  586.                                     $conf->_get_mirror('base'),
  587.                                     substr(uc $author, 0, 1),
  588.                                     substr(uc $author, 0, 2),
  589.                                     uc $author,
  590.                                     @parts,     #possible sub dirs
  591.                                 );
  592.             } else {
  593.                 $auth_obj   = $maybe->author;
  594.                 $path       = $maybe->path;
  595.             }        
  596.         
  597.             if( $maybe->package_name eq $pkg ) {
  598.     
  599.                 my $modobj = CPANPLUS::Module::Fake->new(
  600.                     module  => $maybe->module,
  601.                     version => $version,
  602.                     package => $pkg . '-' . $version . '.' .
  603.                                     $maybe->package_extension,
  604.                     path    => $path,
  605.                     author  => $auth_obj,
  606.                     _id     => $maybe->_id
  607.                 );
  608.                 return $modobj;
  609.  
  610.             ### you asked for a specific version?
  611.             ### assume our $maybe is the one you wanted,
  612.             ### and fix up the version.. 
  613.             } else {
  614.     
  615.                 my $modobj = $maybe->clone;
  616.                 $modobj->version( $version );
  617.                 $modobj->package( 
  618.                         $maybe->package_name .'-'. 
  619.                         $version .'.'. 
  620.                         $maybe->package_extension 
  621.                 );
  622.                 
  623.                 ### you wanted a specific author, but it's not the one
  624.                 ### from the module tree? we'll fix it up
  625.                 if( $author and $author ne $modobj->author->cpanid ) {
  626.                     $modobj->author( $auth_obj );
  627.                     $modobj->path( $path );
  628.                 }
  629.                 
  630.                 return $modobj;
  631.             }
  632.         
  633.         ### you didn't care about a version, so just return the object then
  634.         } elsif ( !$version ) {
  635.             return $maybe;
  636.         }
  637.  
  638.     ### ok, so we can't find it, and it's not an outdated dist either
  639.     ### perhaps we can fake one based on the author name and so on
  640.     } elsif ( $author and $version ) {
  641.  
  642.         ### be extra friendly and pad the .tar.gz suffix where needed
  643.         ### it's just a guess of course, but most dists are .tar.gz
  644.         $dist .= '.tar.gz' unless $dist =~ /\.[A-Za-z]+$/;
  645.  
  646.         ### XXX duplication from above for generating author obj + path...
  647.         my $modobj = CPANPLUS::Module::Fake->new(
  648.             module  => $guess,
  649.             version => $version,
  650.             package => $dist,
  651.             author  => CPANPLUS::Module::Author::Fake->new(
  652.                             author  => uc $author,
  653.                             cpanid  => uc $author,
  654.                             _id     => $self->_id,
  655.                         ),
  656.             path    => File::Spec::Unix->catdir(
  657.                             $conf->_get_mirror('base'),
  658.                             substr(uc $author, 0, 1),
  659.                             substr(uc $author, 0, 2),
  660.                             uc $author,
  661.                             @parts,         #possible subdirs
  662.                         ),
  663.             _id     => $self->_id,
  664.         );
  665.  
  666.         return $modobj;
  667.  
  668.     ### face it, we have /no/ idea what he or she wants...
  669.     ### let's start putting the blame somewhere
  670.     } else {
  671.  
  672.         unless( $author ) {
  673.             error( loc( "'%1' does not contain an author part", $mod ) );
  674.         }
  675.  
  676.         error( loc( "Cannot find '%1' in the module tree", $mod ) );
  677.     }
  678.  
  679.     return;
  680. }
  681.  
  682. =pod
  683.  
  684. =head2 $bool = $cb->reload_indices( [update_source => BOOL, verbose => BOOL] );
  685.  
  686. This method reloads the source files.
  687.  
  688. If C<update_source> is set to true, this will fetch new source files
  689. from your CPAN mirror. Otherwise, C<reload_indices> will do its
  690. usual cache checking and only update them if they are out of date.
  691.  
  692. By default, C<update_source> will be false.
  693.  
  694. The verbose setting defaults to what you have specified in your
  695. config file.
  696.  
  697. Returns true on success and false on failure.
  698.  
  699. =cut
  700.  
  701. sub reload_indices {
  702.     my $self    = shift;
  703.     my %hash    = @_;
  704.     my $conf    = $self->configure_object;
  705.  
  706.     my $tmpl = {
  707.         update_source   => { default    => 0, allow => [qr/^\d$/] },
  708.         verbose         => { default    => $conf->get_conf('verbose') },
  709.     };
  710.  
  711.     my $args = check( $tmpl, \%hash ) or return;
  712.  
  713.     ### make a call to the internal _module_tree, so it triggers cache
  714.     ### file age
  715.     my $uptodate = $self->_check_trees( %$args );
  716.  
  717.  
  718.     return 1 if $self->_build_trees(
  719.                                 uptodate    => $uptodate,
  720.                                 use_stored  => 0,
  721.                                 verbose     => $conf->get_conf('verbose'),
  722.                             );
  723.  
  724.     error( loc( "Error rebuilding source trees!" ) );
  725.  
  726.     return;
  727. }
  728.  
  729. =pod
  730.  
  731. =head2 $bool = $cb->flush(CACHE_NAME)
  732.  
  733. This method allows flushing of caches.
  734. There are several things which can be flushed:
  735.  
  736. =over 4
  737.  
  738. =item * C<methods>
  739.  
  740. The return status of methods which have been attempted, such as
  741. different ways of fetching files.  It is recommended that automatic
  742. flushing be used instead.
  743.  
  744. =item * C<hosts>
  745.  
  746. The return status of URIs which have been attempted, such as
  747. different hosts of fetching files.  It is recommended that automatic
  748. flushing be used instead.
  749.  
  750. =item * C<modules>
  751.  
  752. Information about modules such as prerequisites and whether
  753. installation succeeded, failed, or was not attempted.
  754.  
  755. =item * C<lib>
  756.  
  757. This resets PERL5LIB, which is changed to ensure that while installing
  758. modules they are in our @INC.
  759.  
  760. =item * C<load>
  761.  
  762. This resets the cache of modules we've attempted to load, but failed.
  763. This enables you to load them again after a failed load, if they 
  764. somehow have become available.
  765.  
  766. =item * C<all>
  767.  
  768. Flush all of the aforementioned caches.
  769.  
  770. =back
  771.  
  772. Returns true on success and false on failure.
  773.  
  774. =cut
  775.  
  776. sub flush {
  777.     my $self = shift;
  778.     my $type = shift or return;
  779.  
  780.     my $cache = {
  781.         methods => [ qw( methods load ) ],
  782.         hosts   => [ qw( hosts ) ],
  783.         modules => [ qw( modules lib) ],
  784.         lib     => [ qw( lib ) ],
  785.         load    => [ qw( load ) ],
  786.         all     => [ qw( hosts lib modules methods load ) ],
  787.     };
  788.  
  789.     my $aref = $cache->{$type}
  790.                     or (
  791.                         error( loc("No such cache '%1'", $type) ),
  792.                         return
  793.                     );
  794.  
  795.     return $self->_flush( list => $aref );
  796. }
  797.  
  798. =pod
  799.  
  800. =head2 @mods = $cb->installed()
  801.  
  802. Returns a list of module objects of all your installed modules.
  803. If an error occurs, it will return false.
  804.  
  805. See L<CPANPLUS::Module> for the operations you can perform on a
  806. module object.
  807.  
  808. =cut
  809.  
  810. sub installed {
  811.     my $self = shift;
  812.     my $aref = $self->_all_installed;
  813.  
  814.     return @$aref if $aref;
  815.     return;
  816. }
  817.  
  818. =pod
  819.  
  820. =head2 $bool = $cb->local_mirror([path => '/dir/to/save/to', index_files => BOOL, force => BOOL, verbose => BOOL] )
  821.  
  822. Creates a local mirror of CPAN, of only the most recent sources in a
  823. location you specify. If you set this location equal to a custom host
  824. in your C<CPANPLUS::Config> you can use your local mirror to install
  825. from.
  826.  
  827. It takes the following arguments:
  828.  
  829. =over 4
  830.  
  831. =item path
  832.  
  833. The location where to create the local mirror.
  834.  
  835. =item index_files
  836.  
  837. Enable/disable fetching of index files. You can disable fetching of the
  838. index files if you don't plan to use the local mirror as your primary 
  839. site, or if you'd like up-to-date index files be fetched from elsewhere.
  840.  
  841. Defaults to true.
  842.  
  843. =item force
  844.  
  845. Forces refetching of packages, even if they are there already.
  846.  
  847. Defaults to whatever setting you have in your C<CPANPLUS::Config>.
  848.  
  849. =item verbose
  850.  
  851. Prints more messages about what its doing.
  852.  
  853. Defaults to whatever setting you have in your C<CPANPLUS::Config>.
  854.  
  855. =back
  856.  
  857. Returns true on success and false on error.
  858.  
  859. =cut
  860.  
  861. sub local_mirror {
  862.     my $self = shift;
  863.     my $conf = $self->configure_object;
  864.     my %hash = @_;
  865.  
  866.     my($path, $index, $force, $verbose);
  867.     my $tmpl = {
  868.         path        => { default => $conf->get_conf('base'),
  869.                             store => \$path },
  870.         index_files => { default => 1, store => \$index },
  871.         force       => { default => $conf->get_conf('force'),
  872.                             store => \$force },
  873.         verbose     => { default => $conf->get_conf('verbose'),
  874.                             store => \$verbose },
  875.     };
  876.  
  877.     check( $tmpl, \%hash ) or return;
  878.  
  879.     unless( -d $path ) {
  880.         $self->_mkdir( dir => $path )
  881.                 or( error( loc( "Could not create '%1', giving up", $path ) ),
  882.                     return
  883.                 );
  884.     } elsif ( ! -w _ ) {
  885.         error( loc( "Could not write to '%1', giving up", $path ) );
  886.         return;
  887.     }
  888.  
  889.     my $flag;
  890.     AUTHOR: {
  891.     for my $auth (  sort { $a->cpanid cmp $b->cpanid }
  892.                     values %{$self->author_tree}
  893.     ) {
  894.  
  895.         MODULE: {
  896.         my $i;
  897.         for my $mod ( $auth->modules ) {
  898.             my $fetchdir = File::Spec->catdir( $path, $mod->path );
  899.  
  900.             my %opts = (
  901.                 verbose     => $verbose,
  902.                 force       => $force,
  903.                 fetchdir    => $fetchdir,
  904.             );
  905.  
  906.             ### only do this the for the first module ###
  907.             unless( $i++ ) {
  908.                 $mod->_get_checksums_file(
  909.                             %opts
  910.                         ) or (
  911.                             error( loc( "Could not fetch %1 file, " .
  912.                                         "skipping author '%2'",
  913.                                         CHECKSUMS, $auth->cpanid ) ),
  914.                             $flag++, next AUTHOR
  915.                         );
  916.             }
  917.  
  918.             $mod->fetch( %opts )
  919.                     or( error( loc( "Could not fetch '%1'", $mod->module ) ),
  920.                         $flag++, next MODULE
  921.                     );
  922.         } }
  923.     } }
  924.  
  925.     if( $index ) {
  926.         for my $name (qw[auth dslip mod]) {
  927.             $self->_update_source(
  928.                         name    => $name,
  929.                         verbose => $verbose,
  930.                         path    => $path,
  931.                     ) or ( $flag++, next );
  932.         }
  933.     }
  934.  
  935.     return !$flag;
  936. }
  937.  
  938. =pod
  939.  
  940. =head2 $file = $cb->autobundle([path => OUTPUT_PATH, force => BOOL, verbose => BOOL])
  941.  
  942. Writes out a snapshot of your current installation in C<CPAN> bundle
  943. style. This can then be used to install the same modules for a
  944. different or on a different machine.
  945.  
  946. It will, by default, write to an 'autobundle' directory under your
  947. cpanplus homedirectory, but you can override that by supplying a
  948. C<path> argument.
  949.  
  950. It will return the location of the output file on success and false on
  951. failure.
  952.  
  953. =cut
  954.  
  955. sub autobundle {
  956.     my $self = shift;
  957.     my $conf = $self->configure_object;
  958.     my %hash = @_;
  959.  
  960.     my($path,$force,$verbose);
  961.     my $tmpl = {
  962.         force   => { default => $conf->get_conf('force'), store => \$force },
  963.         verbose => { default => $conf->get_conf('verbose'), store => \$verbose },
  964.         path    => { default => File::Spec->catdir(
  965.                                         $conf->get_conf('base'),
  966.                                         $self->_perl_version( perl => $^X ),
  967.                                         $conf->_get_build('distdir'),
  968.                                         $conf->_get_build('autobundle') ),
  969.                     store => \$path },
  970.     };
  971.  
  972.     check($tmpl, \%hash) or return;
  973.  
  974.     unless( -d $path ) {
  975.         $self->_mkdir( dir => $path )
  976.                 or( error(loc("Could not create directory '%1'", $path ) ),
  977.                     return
  978.                 );
  979.     }
  980.  
  981.     my $name; my $file;
  982.     {   ### default filename for the bundle ###
  983.         my($year,$month,$day) = (localtime)[5,4,3];
  984.         $year += 1900; $month++;
  985.  
  986.         my $ext = 0;
  987.  
  988.         my $prefix  = $conf->_get_build('autobundle_prefix');
  989.         my $format  = "${prefix}_%04d_%02d_%02d_%02d";
  990.  
  991.         BLOCK: {
  992.             $name = sprintf( $format, $year, $month, $day, $ext);
  993.  
  994.             $file = File::Spec->catfile( $path, $name . '.pm' );
  995.  
  996.             -f $file ? ++$ext && redo BLOCK : last BLOCK;
  997.         }
  998.     }
  999.     my $fh;
  1000.     unless( $fh = FileHandle->new( ">$file" ) ) {
  1001.         error( loc( "Could not open '%1' for writing: %2", $file, $! ) );
  1002.         return;
  1003.     }
  1004.     
  1005.     ### make sure we load the module tree *before* doing this, as it
  1006.     ### starts to chdir all over the place
  1007.     $self->module_tree;
  1008.  
  1009.     my $string = join "\n\n",
  1010.                     map {
  1011.                         join ' ',
  1012.                             $_->module,
  1013.                             ($_->installed_version(verbose => 0) || 'undef')
  1014.                     } sort {
  1015.                         $a->module cmp $b->module
  1016.                     }  $self->installed;
  1017.  
  1018.     my $now     = scalar localtime;
  1019.     my $head    = '=head1';
  1020.     my $pkg     = __PACKAGE__;
  1021.     my $version = $self->VERSION;
  1022.     my $perl_v  = join '', `$^X -V`;
  1023.  
  1024.     print $fh <<EOF;
  1025. package $name
  1026.  
  1027. \$VERSION = '0.01';
  1028.  
  1029. 1;
  1030.  
  1031. __END__
  1032.  
  1033. $head NAME
  1034.  
  1035. $name - Snapshot of your installation at $now
  1036.  
  1037. $head SYNOPSIS
  1038.  
  1039. perl -MCPANPLUS -e "install $name"
  1040.  
  1041. $head CONTENTS
  1042.  
  1043. $string
  1044.  
  1045. $head CONFIGURATION
  1046.  
  1047. $perl_v
  1048.  
  1049. $head AUTHOR
  1050.  
  1051. This bundle has been generated autotomatically by
  1052.     $pkg $version
  1053.  
  1054. EOF
  1055.  
  1056.     close $fh;
  1057.  
  1058.     return $file;
  1059. }
  1060.  
  1061. ### XXX these wrappers are not individually tested! only the underlying
  1062. ### code through source.t and indirectly trought he CustomSource plugin.
  1063. =pod
  1064.  
  1065. =head1 CUSTOM MODULE SOURCES
  1066.  
  1067. Besides the sources as provided by the general C<CPAN> mirrors, it's 
  1068. possible to add your own sources list to your C<CPANPLUS> index.
  1069.  
  1070. The methodology behind this works much like C<Debian's apt-sources>.
  1071.  
  1072. The methods below show you how to make use of this functionality. Also
  1073. note that most of these methods are available through the default shell
  1074. plugin command C</cs>, making them available as shortcuts through the
  1075. shell and via the commandline.
  1076.  
  1077. =head2 %files = $cb->list_custom_sources
  1078.  
  1079. Returns a mapping of registered custom sources and their local indices
  1080. as follows:
  1081.  
  1082.     /full/path/to/local/index => http://remote/source
  1083.  
  1084. Note that any file starting with an C<#> is being ignored.
  1085.  
  1086. =cut
  1087.  
  1088. sub list_custom_sources {
  1089.     return shift->__list_custom_module_sources( @_ );
  1090. }
  1091.  
  1092. =head2 $local_index = $cb->add_custom_source( uri => URI, [verbose => BOOL] );
  1093.  
  1094. Adds an C<URI> to your own sources list and mirrors its index. See the 
  1095. documentation on C<< $cb->update_custom_source >> on how this is done.
  1096.  
  1097. Returns the full path to the local index on success, or false on failure.
  1098.  
  1099. Note that when adding a new C<URI>, the change to the in-memory tree is
  1100. not saved until you rebuild or save the tree to disk again. You can do 
  1101. this using the C<< $cb->reload_indices >> method.
  1102.  
  1103. =cut
  1104.  
  1105. sub add_custom_source {
  1106.     return shift->_add_custom_module_source( @_ );
  1107. }
  1108.  
  1109. =head2 $local_index = $cb->remove_custom_source( uri => URI, [verbose => BOOL] );
  1110.  
  1111. Removes an C<URI> from your own sources list and removes its index.
  1112.  
  1113. To find out what C<URI>s you have as part of your own sources list, use
  1114. the C<< $cb->list_custom_sources >> method.
  1115.  
  1116. Returns the full path to the deleted local index file on success, or false
  1117. on failure.
  1118.  
  1119. =cut
  1120.  
  1121. ### XXX do clever dispatching based on arg number?
  1122. sub remove_custom_source {
  1123.     return shift->_remove_custom_module_source( @_ );
  1124. }
  1125.  
  1126. =head2 $bool = $cb->update_custom_source( [remote => URI] );
  1127.  
  1128. Updates the indexes for all your custom sources. It does this by fetching
  1129. a file called C<packages.txt> in the root of the custom sources's C<URI>.
  1130. If you provide the C<remote> argument, it will only update the index for
  1131. that specific C<URI>.
  1132.  
  1133. Here's an example of how custom sources would resolve into index files:
  1134.  
  1135.   file:///path/to/sources       =>  file:///path/to/sources/packages.txt
  1136.   http://example.com/sources    =>  http://example.com/sources/packages.txt
  1137.   ftp://example.com/sources     =>  ftp://example.com/sources/packages.txt
  1138.   
  1139. The file C<packages.txt> simply holds a list of packages that can be found
  1140. under the root of the C<URI>. This file can be automatically generated for
  1141. you when the remote source is a C<file:// URI>. For C<http://>, C<ftp://>,
  1142. and similar, the administrator of that repository should run the method
  1143. C<< $cb->write_custom_source_index >> on the repository to allow remote
  1144. users to index it.
  1145.  
  1146. For details, see the C<< $cb->write_custom_source_index >> method below.
  1147.  
  1148. All packages that are added via this mechanism will be attributed to the
  1149. author with C<CPANID> C<LOCAL>. You can use this id to search for all 
  1150. added packages.
  1151.  
  1152. =cut
  1153.  
  1154. sub update_custom_source {
  1155.     my $self = shift;
  1156.     
  1157.     ### if it mentions /remote/, the request is to update a single uri,
  1158.     ### not all the ones we have, so dispatch appropriately
  1159.     my $rv = grep( /remote/i, @_)
  1160.         ? $self->__update_custom_module_source( @_ )
  1161.         : $self->__update_custom_module_sources( @_ );
  1162.  
  1163.     return $rv;
  1164. }    
  1165.  
  1166. =head2 $file = $cb->write_custom_source_index( path => /path/to/package/root, [to => /path/to/index/file, verbose => BOOL] );
  1167.  
  1168. Writes the index for a custom repository root. Most users will not have to 
  1169. worry about this, but administrators of a repository will need to make sure
  1170. their indexes are up to date.
  1171.  
  1172. The index will be written to a file called C<packages.txt> in your repository
  1173. root, which you can specify with the C<path> argument. You can override this
  1174. location by specifying the C<to> argument, but in normal operation, that should
  1175. not be required.
  1176.  
  1177. Once the index file is written, users can then add the C<URI> pointing to 
  1178. 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.
  1179.  
  1180. =cut
  1181.  
  1182. sub write_custom_source_index {
  1183.     return shift->__write_custom_module_index( @_ );
  1184. }
  1185.  
  1186. 1;
  1187.  
  1188. =pod
  1189.  
  1190. =head1 BUG REPORTS
  1191.  
  1192. Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>.
  1193.  
  1194. =head1 AUTHOR
  1195.  
  1196. This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
  1197.  
  1198. =head1 COPYRIGHT
  1199.  
  1200. The CPAN++ interface (of which this module is a part of) is copyright (c) 
  1201. 2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved.
  1202.  
  1203. This library is free software; you may redistribute and/or modify it 
  1204. under the same terms as Perl itself.
  1205.  
  1206. =head1 SEE ALSO
  1207.  
  1208. L<CPANPLUS::Configure>, L<CPANPLUS::Module>, L<CPANPLUS::Module::Author>, 
  1209. L<CPANPLUS::Selfupdate>
  1210.  
  1211. =cut
  1212.  
  1213. # Local variables:
  1214. # c-indentation-style: bsd
  1215. # c-basic-offset: 4
  1216. # indent-tabs-mode: nil
  1217. # End:
  1218. # vim: expandtab shiftwidth=4:
  1219.  
  1220. __END__
  1221.  
  1222. todo:
  1223. sub dist {          # not sure about this one -- probably already done
  1224.                       enough in Module.pm
  1225. sub reports {       # in Module.pm, wrapper here
  1226.  
  1227.  
  1228.