2 # $Id: cpan,v 1.9 2006/11/01 21:49:31 comdog Exp $
7 cpan - easily interact with CPAN from the command line
11 # with arguments and no switches, installs specified modules
12 cpan module_name [ module_name ... ]
14 # with switches, installs modules with extra behavior
15 cpan [-cfimt] module_name [ module_name ... ]
17 # without arguments, starts CPAN.pm shell
20 # without arguments, but some switches
25 This script provides a command interface (not a shell) to CPAN. At the
26 moment it uses CPAN.pm to do the work, but it is not a one-shot command
31 These options are mutually exclusive, and the script processes them in
32 this order: [hvCAar]. Once the script finds one, it ignores the others,
33 and then exits after it finishes the task. The script ignores any other
40 Creates the CPAN.pm autobundle with CPAN::Shell->autobundle.
42 =item -A module [ module ... ]
44 Shows the primary maintainers for the specified modules
46 =item -C module [ module ... ]
48 Show the C<Changes> files for the specified modules
50 =item -D module [ module ... ]
52 Show the module details. This prints one line for each out-of-date module
53 (meaning, modules locally installed but have newer versions on CPAN).
54 Each line has three columns: module name, local version, and CPAN
57 =item -L author [ author ... ]
59 List the modules by the specified authors.
63 Prints a help message.
67 Show the out-of-date modules.
71 Recompiles dynamically loaded modules with CPAN::Shell->recompile.
75 Print the script version and CPAN.pm version.
81 These options are mutually exclusive, and the script processes them in
82 alphabetical order. It only processes the first one it finds.
88 Runs a `make clean` in the specified module's directories.
92 Forces the specified action, when it normally would have failed.
96 Installed the specified modules.
100 Makes the specified modules.
104 Runs a `make test` on the specified modules.
110 # print a help message
113 # print the version numbers
116 # create an autobundle
122 # install modules ( sole -i is optional )
123 cpan -i Netscape::Booksmarks Business::ISBN
125 # force install modules ( must use -i )
126 cpan -fi CGI::Minimal URI
137 Most behaviour, including environment variables and configuration,
138 comes directly from CPAN.pm.
140 =head1 SOURCE AVAILABILITY
142 This source is part of a SourceForge project which always has the
143 latest sources in CVS, as well as all of the previous releases.
145 http://sourceforge.net/projects/brian-d-foy/
147 If, for some reason, I disappear from the world, one of the other
148 members of the project can shepherd this module appropriately.
152 Japheth Cleaver added the bits to allow a forced install (-f).
154 Jim Brandt suggest and provided the initial implementation for the
155 up-to-date and Changes features.
157 Adam Kennedy pointed out that exit() causes problems on Windows
158 where this script ends up with a .bat extension
162 brian d foy, C<< <bdfoy@cpan.org> >>
166 Copyright (c) 2001-2006, brian d foy, All Rights Reserved.
168 You may redistribute this under the same terms as Perl itself.
176 sprintf "%d.%d", q$Revision: 1.9 $ =~ m/ (\d+) \. (\d+) /xg;
178 if( $ARGV[0] eq 'install' )
184 It looks like you specified 'install' as an argument to cpan(1). This
185 script is not the CPAN.pm prompt and doesn't understand the same commands.
186 In fact, doesn't require the extra typing. You probably just want to
187 list the modules you want to install:
191 See the documentation for more details on using this script.
195 if( 0 == @ARGV ) { CPAN::shell(); exit 0 }
197 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
198 # set up the order of options that we layer over CPAN::Shell
199 my @META_OPTIONS = qw( h v C A D O L a r );
201 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
202 # map switches to method names in CPAN::Shell
203 my $Default = 'default';
206 $Default => 'install',
213 my @CPAN_OPTIONS = grep { $_ ne $Default } sort keys %CPAN_METHODS;
215 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
216 # map switches to the subroutines in this script, along with other information.
217 # use this stuff instead of hard-coded indices and values
219 # key => [ sub ref, takes args?, exit value, description ]
220 h => [ \&_print_help, 0, 0, 'Printing help' ],
221 v => [ \&_print_version, 0, 0, 'Printing version' ],
222 C => [ \&_show_Changes, 1, 0, 'Showing Changes file' ],
223 A => [ \&_show_Author, 1, 0, 'Showing Author' ],
224 D => [ \&_show_Details, 1, 0, 'Showing Details' ],
225 O => [ \&_show_out_of_date, 0, 0, 'Showing Out of date' ],
226 L => [ \&_show_author_mods, 1, 0, 'Showing author mods' ],
227 a => [ \&_create_autobundle, 0, 0, 'Creating autobundle' ],
228 r => [ \&_recompile, 0, 0, 'Recompiling' ],
230 c => [ \&_default, 1, 0, 'Running `make clean`' ],
231 f => [ \&_default, 1, 0, 'Installing with force' ],
232 i => [ \&_default, 1, 0, 'Running `make install`' ],
233 'm' => [ \&_default, 1, 0, 'Running `make`' ],
234 t => [ \&_default, 1, 0, 'Running `make test`' ],
238 my %Method_table_index = (
245 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
246 # finally, do some argument processing
247 my @option_order = ( @META_OPTIONS, @CPAN_OPTIONS );
250 Getopt::Std::getopts(
251 join( '', @option_order ), \%options );
253 my $option_count = grep { $options{$_} } @option_order;
254 $option_count -= $options{'f'}; # don't count force
256 # if there are no options, set -i (this line fixes RT ticket 16915)
257 $options{i}++ unless $option_count;
259 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
260 # try each of the possible switches until we find one to handle
261 # print an error message if there are too many switches
262 # print an error message if there are arguments when there shouldn't be any
263 foreach my $option ( @option_order )
265 next unless $options{$option};
267 ref $Method_table{$option}[ $Method_table_index{code} ] eq ref sub {};
269 print "$Method_table{$option}[ $Method_table_index{description} ] " .
270 "-- ignoring other opitions\n" if $option_count > 1;
271 print "$Method_table{$option}[ $Method_table_index{description} ] " .
272 "-- ignoring other arguments\n"
273 if( @ARGV && ! $Method_table{$option}[ $Method_table_index{takes_args} ] );
275 $Method_table{$option}[ $Method_table_index{code} ]->( \@ARGV );
280 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
281 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
282 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
290 # choose the option that we're going to use
291 # we'll deal with 'f' (force) later, so skip it
292 foreach my $option ( @CPAN_OPTIONS )
294 next if $option eq 'f';
295 next unless $options{$option};
300 # 1. with no switches, but arguments, use the default switch (install)
301 # 2. with no switches and no args, start the shell
302 # 3. With a switch but no args, die! These switches need arguments.
303 if( not $switch and @$args ) { $switch = $Default; }
304 elsif( not $switch and not @$args ) { CPAN::shell(); return }
305 elsif( $switch and not @$args )
306 { die "Nothing to $CPAN_METHODS{$switch}!\n"; }
308 # Get and cheeck the method from CPAN::Shell
309 my $method = $CPAN_METHODS{$switch};
310 die "CPAN.pm cannot $method!\n" unless CPAN::Shell->can( $method );
312 # call the CPAN::Shell method, with force if specified
313 foreach my $arg ( @$args )
315 if( $options{f} ) { CPAN::Shell->force( $method, $arg ) }
316 else { CPAN::Shell->$method( $arg ) }
320 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
323 print STDERR "Use perldoc to read the documentation\n";
329 print STDERR "$0 script version $VERSION, CPAN.pm version " .
330 CPAN->VERSION . "\n";
333 sub _create_autobundle
335 print "Creating autobundle in ", $CPAN::Config->{cpan_home},
338 CPAN::Shell->autobundle;
343 print "Recompiling dynamically-loaded extensions\n";
345 CPAN::Shell->recompile;
352 foreach my $arg ( @$args )
354 print "Checking $arg\n";
355 my $module = CPAN::Shell->expand( "Module", $arg );
357 next unless $module->inst_file;
358 #next if $module->uptodate;
360 ( my $id = $module->id() ) =~ s/::/\-/;
362 my $url = "http://search.cpan.org/~" . lc( $module->userid ) . "/" .
363 $id . "-" . $module->cpan_version() . "/";
365 #print "URL: $url\n";
366 _get_changes_file($url);
370 sub _get_changes_file
372 die "Reading Changes files requires LWP::Simple and URI\n"
373 unless eval { require LWP::Simple; require URI; };
377 my $content = LWP::Simple::get( $url );
378 print "Got $url ...\n" if defined $content;
381 my( $change_link ) = $content =~ m|<a href="(.*?)">Changes</a>|gi;
383 my $changes_url = URI->new_abs( $change_link, $url );
384 #print "change link is: $changes_url\n";
385 my $changes = LWP::Simple::get( $changes_url );
386 #print "change text is: " . $change_link->text() . "\n";
394 foreach my $arg ( @$args )
396 my $module = CPAN::Shell->expand( "Module", $arg );
397 my $author = CPAN::Shell->expand( "Author", $module->userid );
399 next unless $module->userid;
401 printf "%-25s %-8s %-25s %s\n",
402 $arg, $module->userid, $author->email, $author->fullname;
410 foreach my $arg ( @$args )
412 my $module = CPAN::Shell->expand( "Module", $arg );
413 my $author = CPAN::Shell->expand( "Author", $module->userid );
415 next unless $module->userid;
417 print "$arg\n", "-" x 73, "\n\t";
419 $module->description ? $module->description : "(no description)",
422 'Installed: ' . $module->inst_version,
423 'CPAN: ' . $module->cpan_version . ' ' .
424 ($module->uptodate ? "" : "Not ") . "up to date",
425 $author->fullname . " (" . $module->userid . ")",
432 sub _show_out_of_date
434 my @modules = CPAN::Shell->expand( "Module", "/./" );
436 printf "%-40s %6s %6s\n", "Module Name", "Local", "CPAN";
437 print "-" x 73, "\n";
439 foreach my $module ( @modules )
441 next unless $module->inst_file;
442 next if $module->uptodate;
443 printf "%-40s %.4f %.4f\n",
445 $module->inst_version ? $module->inst_version : '',
446 $module->cpan_version;
451 sub _show_author_mods
455 my %hash = map { lc $_, 1 } @$args;
457 my @modules = CPAN::Shell->expand( "Module", "/./" );
459 foreach my $module ( @modules )
461 next unless exists $hash{ lc $module->userid };
462 print $module->id, "\n";