5 use CPANPLUS::Internals::Constants;
9 use File::Temp qw|tempfile|;
11 use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
13 local $Data::Dumper::Indent = 1;
15 use constant PREREQ_SKIP_CLASS => 'CPANPLUS::To::Dist::PREREQ_SKIP';
16 use constant ALARM_CLASS => 'CPANPLUS::To::Dist::ALARM';
18 ### print when you can
21 my $cb = CPANPLUS::Backend->new
22 or die loc("Could not create new CPANPLUS::Backend object");
23 my $conf = $cb->configure_object;
25 my %formats = map { $_ => $_ } CPANPLUS::Dist->dist_types;
29 'format=s', 'archive',
31 'skiptest!', 'keepsource!',
32 'makefile!', 'buildprereq!',
34 'ban=s@', 'banlist=s@',
35 'ignore=s@', 'ignorelist=s@',
36 'defaults', 'modulelist=s@',
37 'logfile=s', 'timeout=s',
38 'dist-opts=s%', 'set-config=s%',
39 'default-banlist!', 'set-program=s%',
40 'default-ignorelist!', 'edit-metafile!',
44 die usage() if exists $opts->{'help'};
47 my $tarball = $opts->{'archive'} || 0;
48 my $keep = $opts->{'keepsource'} ? 1 : 0;
49 my $prereqbuild = exists $opts->{'buildprereq'}
50 ? $opts->{'buildprereq'}
52 my $timeout = exists $opts->{'timeout'}
56 ### use default answers?
57 $ENV{'PERL_MM_USE_DEFAULT'} = $opts->{'defaults'} ? 1 : 0;
60 ### if provided, we go with the command line option, fall back to conf setting
61 { $format = $opts->{'format'} || $conf->get_conf('dist_type');
62 $conf->set_conf( dist_type => $format );
64 ### is this a valid format??
65 die loc("Invalid format: " . ($format || "[NONE]") ) . usage()
66 unless $formats{$format};
68 ### any options to fix config entries
69 { my $set_conf = $opts->{'set-config'} || {};
70 while( my($key,$val) = each %$set_conf ) {
71 $conf->set_conf( $key => $val );
75 ### any options to fix program entries
76 { my $set_prog = $opts->{'set-program'} || {};
77 while( my($key,$val) = each %$set_prog ) {
78 $conf->set_program( $key => $val );
82 ### any other options passed
83 { my %map = ( verbose => 'verbose',
85 skiptest => 'skiptest',
86 makefile => 'prefer_makefile'
89 ### set config options from arguments
90 while (my($key,$val) = each %map) {
91 my $bool = exists $opts->{$key}
93 : $conf->get_conf($val);
94 $conf->set_conf( $val => $bool );
100 if( exists $opts->{'modulelist'} ) {
101 push @modules, map { parse_file( $_ ) } @{ $opts->{'modulelist'} };
104 die usage() unless @modules;
106 ### set up munge callback if requested
107 { if( $opts->{'edit-metafile'} ) {
108 my $editor = $conf->get_program('editor');
112 ### register install callback ###
113 $cb->_register_callback(
114 name => 'munge_dist_metafile',
117 my $text = shift or return;
119 my($fh,$file) = tempfile( UNLINK => 1 );
121 unless( print $fh $text ) {
122 warn "Could not print metafile information: $!";
128 system( $editor => $file );
130 my $cont = $cb->_get_file_contents( file => $file );
137 warn "No editor configured. Can not edit metafiles!\n";
144 if( my $file = $opts->{logfile} ) {
145 open $fh, ">$file" or (
146 warn loc("Could not open '%1' for writing: %2", $file,$!),
150 warn "Logging to '$file'\n";
157 ### reload indices if so desired
158 $cb->reload_indices() if $opts->{'flushcache'};
160 { my @ban = exists $opts->{'ban'}
161 ? map { qr/$_/ } @{ $opts->{'ban'} }
165 if( exists $opts->{'banlist'} ) {
166 push @ban, map { parse_file( $_, 1 ) } @{ $opts->{'banlist'} };
169 push @ban, map { s/\s+//; $_ }
170 map { [split /\s*#\s*/]->[0] }
172 map { split /\n/ } _default_ban_list()
173 if $opts->{'default-banlist'};
175 ### use our prereq install callback
176 $conf->set_conf( prereqs => PREREQ_ASK );
178 ### register install callback ###
179 $cb->_register_callback(
180 name => 'install_prerequisite',
181 code => \&__ask_about_install,
185 ### check for ban patterns when handling prereqs
186 sub __ask_about_install {
188 my $mod = shift or return;
189 my $prereq = shift or return;
192 ### die with an error object, so we can verify that
193 ### the die came from this location, and that it's an
194 ### 'acceptable' death
195 my $pat = ban_me( $prereq );
196 die bless sub { loc("Module '%1' requires '%2' to be installed " .
197 "but found in your ban list (%3) -- skipping",
198 $mod->module, $prereq->module, $pat )
199 }, PREREQ_SKIP_CLASS if $pat;
203 ### should we skip this module?
207 for my $pat ( @ban ) {
208 return $pat if $mod->module =~ /$pat/i;
214 ### patterns to strip from prereq lists
215 { my @ignore = exists $opts->{'ignore'}
216 ? map { qr/$_/ } @{ $opts->{'ignore'} }
219 if( exists $opts->{'ignorelist'} ) {
220 push @ignore, map { parse_file( $_, 1 ) } @{ $opts->{'ignorelist'} };
223 push @ignore, map { s/\s+//; $_ }
224 map { [split /\s*#\s*/]->[0] }
226 map { split /\n/ } _default_ignore_list()
227 if $opts->{'default-ignorelist'};
230 ### register install callback ###
231 $cb->_register_callback(
232 name => 'filter_prereqs',
233 code => \&__filter_prereqs,
236 sub __filter_prereqs {
240 for my $name ( keys %$href ) {
241 my $obj = $cb->parse_module( module => $name ) or (
242 warn "Cannot make a module object out of ".
243 "'$name' -- skipping\n",
246 if( my $pat = ignore_me( $obj ) ) {
247 warn loc("'%1' found in your ignore list (%2) ".
248 "-- filtering it out\n", $name, $pat);
250 delete $href->{ $name };
257 ### should we skip this module?
261 for my $pat ( @ignore ) {
262 return $pat if $mod->module =~ /$pat/i;
263 return $pat if $mod->package_name =~ /$pat/i;
271 for my $name (@modules) {
275 ### is it a tarball? then we get it locally and transform it
276 ### and its dependencies into .debs
278 ### make sure we use an absolute path, so chdirs() dont
280 $name = File::Spec->rel2abs( $name );
284 warn loc("Archive '$name' does not exist");
288 $obj = CPANPLUS::Module::Fake->new(
289 module => basename($name),
290 path => dirname($name),
291 package => basename($name),
294 ### if it's a traditional CPAN package, we can tidy
295 ### up the module name some
296 $obj->module( $obj->package_name ) if $obj->package_name;
298 ### get the version from the package name
299 $obj->version( $obj->package_version || 0 );
301 ### set the location of the tarball
302 $obj->status->fetch($name);
304 ### plain old cpan module?
307 ### find the corresponding module object ###
308 $obj = $cb->parse_module( module => $name ) or (
309 warn "Cannot make a module object out of ".
310 "'$name' -- skipping\n",
315 if( my $pat = ban_me( $obj ) ) {
316 warn loc("'%1' found in your ban list (%2) -- skipping\n",
317 $obj->module, $pat );
321 ### or just ignored it?
322 if( my $pat = ignore_me( $obj ) ) {
323 warn loc("'%1' found in your ignore list (%2) -- skipping\n",
324 $obj->module, $pat );
329 my $target = $opts->{'install'} ? 'install' : 'create';
331 local $SIG{ALRM} = sub { die bless {}, ALARM_CLASS }
336 my $dist_opts = $opts->{'dist-opts'} || {};
338 my $rv = $obj->install(
339 prereq_target => $target,
341 keep_source => $keep,
342 prereq_build => $prereqbuild,
344 ### any passed arbitrary options
353 ### set here again, in case the install dies
356 ### install failed due to a 'die' in our prereq skipper?
357 if( $@ and ref $@ and $@->isa( PREREQ_SKIP_CLASS ) ) {
358 warn loc("Dist creation of '%1' skipped: '%2'",
359 $obj->module, $@->() );
362 } elsif ( $@ and ref $@ and $@->isa( ALARM_CLASS ) ) {
363 warn loc("\nDist creation of '%1' skipped, build time exceeded: ".
364 "%2 seconds\n", $obj->module, $timeout );
367 ### died for some other reason? just report and skip
369 warn loc("Dist creation of '%1' failed: '%2'",
374 ### we didn't get a dist object back?
375 unless ($dist and $obj->status->dist) {
376 warn loc("Unable to create '%1' dist of '%2'", $format, $obj->module);
380 print "Created '$format' distribution for ", $obj->module,
381 " to:\n\t", $obj->status->dist->status->dist, "\n";
386 my $file = shift or return;
387 my $qr = shift() ? 1 : 0;
389 my $fh = OPEN_FILE->( $file ) or return;
394 next if /^#/; # skip comments
395 next unless /\S/; # skip empty lines
396 s/^(\S+).*/$1/; # skip extra info
397 push @rv, $qr ? qr/$_/ : $_; # add pattern to the list
405 cpan2dist - The CPANPLUS distribution creator
409 This script will create distributions of C<CPAN> modules of the format
410 you specify, including its prerequisites. These packages can then be
411 installed using the corresponding package manager for the format.
413 Note, you can also do this interactively from the default shell,
414 C<CPANPLUS::Shell::Default>. See the C<CPANPLUS::Dist> documentation,
415 as well as the documentation of your format of choice for any format
416 specific documentation.
423 my $me = basename($0);
424 my $formats = join "\n", map { "\t\t$_" } sort keys %formats;
426 my $usage = << '=cut';
429 Usage: cpan2dist [--format FMT] [OPTS] Mod::Name [Mod::Name, ...]
430 cpan2dist [--format FMT] [OPTS] --modulelist /tmp/mods.list
431 cpan2dist [--format FMT] [OPTS] --archive /tmp/dist [/tmp/dist2]
433 Will create a distribution of type FMT of the modules
434 specified on the command line, and all their prerequisites.
436 Can also create a distribution of type FMT from a local
437 archive and all of its prerequisites.
442 Possible formats are:
445 You can install more formats from CPAN!
453 ### take no argument:
454 --help Show this help message
455 --install Install this package (and any prerequisites you built)
457 --skiptest Skip tests. Can be negated using --noskiptest
458 --force Force operation. Can be negated using --noforce
459 --verbose Be verbose. Can be negated using --noverbose
460 --keepsource Keep sources after building distribution. Can be
461 negated by --nokeepsource. May not be supported
463 --makefile Prefer Makefile.PL over Build.PL. Can be negated
464 using --nomakefile. Defaults to your config setting
465 --buildprereq Build packages of any prerequisites, even if they are
466 already uptodate on the local system. Can be negated
467 using --nobuildprereq. Defaults to false.
468 --archive Indicate that all modules listed are actually archives
469 --flushcache Update CPANPLUS' cache before commencing any operation
470 --defaults Instruct ExtUtils::MakeMaker and Module::Build to use
471 default answers during 'perl Makefile.PL' or 'perl
472 Build.PL' calls where possible
473 --edit-metafile Edit the distributions metafile(s) before the distribution
474 is built. Requires a configured editor.
477 --format Installer format to use (defaults to config setting)
478 --ban Patterns of module names to skip during installation,
479 case-insensitive (affects prerequisites too)
480 May be given multiple times
481 --banlist File containing patterns that could be given to --ban
482 Are appended to the ban list built up by --ban
483 May be given multiple times.
484 --ignore Patterns of modules to exclude from prereq list. Useful
485 for when a prereq listed by a CPAN module is resolved
486 in another way than from its corresponding CPAN package
487 (Match is done on both module name, and package name of
488 the package the module is in, case-insensitive)
489 --ignorelist File containing patterns that may be given to --ignore.
490 Are appended to the ban list built up by --ignore.
491 May be given multiple times.
492 --modulelist File containing a list of modules that should be built.
493 Are appended to the list of command line modules.
494 May be given multiple times.
495 --logfile File to log all output to. By default, all output goes
497 --timeout The allowed time for buliding a distribution before
498 aborting. This is useful to terminate any build that
499 hang or happen to be interactive despite being told not
500 to be. Defaults to 300 seconds. To turn off, you can
502 --set-config Change any options as specified in your config for this
503 invocation only. See CPANPLUS::Config for a list of
505 --set-program Change any programs as specified in your config for this
506 invocation only. See CPANPLUS::Config for a list of
508 --dist-opts Arbitrary options passed along to the chosen installer
509 format's prepare()/create() routine. Please see the
510 documentation of the installer of your choice for
514 --default-banlist Use our builtin banlist. Works just like --ban
515 and --banlist, but with pre-set lists. See the
516 "Builtin Lists" section for details.
517 --default-ignorelist Use our builtin ignorelist. Works just like
518 --ignore and --ignorelist but with pre-set lists.
519 See the "Builtin Lists" section for details.
523 ### build a debian package of DBI and its prerequisites,
524 ### don't bother running tests
525 cpan2dist --format CPANPLUS::Dist::Deb --buildprereq --skiptest DBI
527 ### build a debian package of DBI and its prerequisites and install them
528 cpan2dist --format CPANPLUS::Dist::Deb --buildprereq --install DBI
530 ### Build a package, whose format is determined by your config, of
531 ### the local tarball, reloading cpanplus' indices first and using
532 ### the tarballs Makefile.PL if it has one.
533 cpan2dist --makefile --flushcache --archive /path/to/Cwd-1.0.tgz
535 ### build a package from Net::FTP, but dont build any packages or
536 ### dependencies whose name match 'Foo', 'Bar' or any of the
537 ### patterns mentioned in /tmp/ban
538 cpan2dist --ban Foo --ban Bar --banlist /tmp/ban Net::FTP
540 ### build a package from Net::FTP, but ignore its listed dependency
541 ### on IO::Socket, as it's shipped per default with the OS we're on
542 cpan2dist --ignore IO::Socket Net::FTP
544 ### building all modules listed, plus their prerequisites
545 cpan2dist --ignorelist /tmp/modules.ignore --banlist /tmp/modules.ban
546 --modulelist /tmp/modules.list --buildprereq --flushcache
547 --makefile --defaults
549 ### pass arbitrary options to the format's prepare()/create() routine
550 cpan2dist --dist-opts deb_version=3 --dist-opts prefix=corp
557 Ignore list:] . _default_ignore_list() . qq[
558 Ban list:] . _default_ban_list();
560 ### strip the pod directives
561 $usage =~ s/=pod\n//g;
568 =head1 Built-In Filter Lists
570 Some modules you'd rather not package. Some because they
571 are part of core-perl and you dont want a new package.
572 Some because they won't build on your system. Some because
573 your package manager of choice already packages them for you.
575 There may be a myriad of reasons. You can use the C<--ignore>
576 and C<--ban> options for this, but we provide some built-in
577 lists that catch common cases. You can use these built-in lists
578 if you like, or supply your own if need be.
580 =head2 Built-In Ignore List
584 You can use this list of regexes to ignore modules matching
585 to be listed as prerequisites of a package. Particulaly useful
586 if they are bundled with core-perl anyway and they have known
589 Toggle it by supplying the C<--default-ignorelist> option.
593 sub _default_ignore_list {
595 my $list = << '=cut';
598 ^IO$ # Provided with core anyway
599 ^Cwd$ # Provided with core anyway
600 ^File::Spec # Provided with core anyway
601 ^Config$ # Perl's own config, not shipped separately
602 ^ExtUtils::MakeMaker$ # Shipped with perl, recent versions
603 # have bug 14721 (see rt.cpan.org)
604 ^ExtUtils::Install$ # Part of of EU::MM, same reason
611 =head2 Built-In Ban list
613 You can use this list of regexes to disable building of these
616 Toggle it by supplying the C<--default-banlist> option.
620 sub _default_ban_list {
622 my $list = << '=cut';
625 ^GD$ # Needs c libaries
626 ^Berk.*DB # DB packages require specific options & linking
627 ^DBD:: # DBD drives require database files/headers
628 ^XML:: # XML modules usually require expat libraries
629 Apache # These usually require apache libraries
630 SSL # These usually require SSL certificates & libs
631 Image::Magick # Needs ImageMagick C libraries
632 Mail::ClamAV # Needs ClamAV C Libraries
633 ^Verilog # Needs Verilog C Libraries
634 ^Authen::PAM$ # Needs PAM C libraries & Headers
645 L<CPANPLUS::Dist>, L<CPANPLUS::Module>, L<CPANPLUS::Shell::Default>,
650 Please report bugs or other issues to E<lt>bug-cpanplus@rt.cpan.org<gt>.
654 This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
658 The CPAN++ interface (of which this module is a part of) is copyright (c)
659 2001 - 2007, Jos Boumans E<lt>kane@cpan.orgE<gt>. All rights reserved.
661 This library is free software; you may redistribute and/or modify it
662 under the same terms as Perl itself.
667 # c-indentation-style: bsd
669 # indent-tabs-mode: nil
671 # vim: expandtab shiftwidth=4: