]> git.vpit.fr Git - perl/modules/CPANPLUS-Dist-Gentoo.git/blob - lib/CPANPLUS/Dist/Gentoo.pm
a3264bb0d6ee34e0573061862a8ac3c460b23aba
[perl/modules/CPANPLUS-Dist-Gentoo.git] / lib / CPANPLUS / Dist / Gentoo.pm
1 package CPANPLUS::Dist::Gentoo;
2
3 use strict;
4 use warnings;
5
6 use Cwd        ();
7 use List::Util qw/reduce/;
8 use File::Copy ();
9 use File::Path ();
10 use File::Spec;
11
12 use IPC::Cmd          ();
13 use Parse::CPAN::Meta ();
14
15 use CPANPLUS::Error ();
16
17 use base qw/CPANPLUS::Dist::Base/;
18
19 use CPANPLUS::Dist::Gentoo::Atom;
20 use CPANPLUS::Dist::Gentoo::Maps;
21
22 =head1 NAME
23
24 CPANPLUS::Dist::Gentoo - CPANPLUS backend generating Gentoo ebuilds.
25
26 =head1 VERSION
27
28 Version 0.09
29
30 =cut
31
32 our $VERSION = '0.09';
33
34 =head1 SYNOPSIS
35
36     cpan2dist --format=CPANPLUS::Dist::Gentoo \
37               --dist-opts overlay=/usr/local/portage \
38               --dist-opts distdir=/usr/portage/distfiles \
39               --dist-opts manifest=yes \
40               --dist-opts keywords=x86 \
41               --dist-opts header="# Copyright 1999-2008 Gentoo Foundation" \
42               --dist-opts footer="# End" \
43               Any::Module You::Like
44
45 =head1 DESCRPITON
46
47 This module is a CPANPLUS backend that recursively generates Gentoo ebuilds for a given package in the specified overlay (defaults to F</usr/local/portage>), updates the manifest, and even emerges it (together with its dependencies) if the user requires it.
48 You need write permissions on the directory where Gentoo fetches its source files (usually F</usr/portage/distfiles>).
49 The valid C<KEYWORDS> for the generated ebuilds are by default those given in C<ACCEPT_KEYWORDS>, but you can specify your own with the C<keywords> dist-option.
50
51 The generated ebuilds are placed into the C<perl-gcpanp> category.
52 They favour depending on a C<virtual>, on C<perl-core>, C<dev-perl> or C<perl-gcpan> (in that order) rather than C<perl-gcpanp>.
53
54 =head1 INSTALLATION
55
56 Before installing this module, you should append C<perl-gcpanp> to your F</etc/portage/categories> file.
57
58 You have two ways for installing this module :
59
60 =over 4
61
62 =item *
63
64 Use the perl overlay located at L<http://git.overlays.gentoo.org/gitweb/?p=proj/perl-overlay.git>.
65 It contains an ebuild for L<CPANPLUS::Dist::Gentoo>.
66
67 =item *
68
69 Bootstrap an ebuild for L<CPANPLUS::Dist::Gentoo> using itself.
70 Note that if your Gentoo system C<perl> is C<5.8.x>, L<CPANPLUS> and its dependencies are not installed and not even available in the main portage tree.
71 So you need to bootstrap them as well.
72
73 First, fetch tarballs for L<CPANPLUS> and L<CPANPLUS::Dist::Gentoo> :
74
75     $ cd /tmp
76     $ wget http://search.cpan.org/CPAN/authors/id/B/BI/BINGOS/CPANPLUS-0.9003.tar.gz
77     $ wget http://search.cpan.org/CPAN/authors/id/V/VP/VPIT/CPANPLUS-Dist-Gentoo-0.09.tar.gz
78
79 Log in as root and unpack them in e.g. your home directory :
80
81     # cd
82     # tar xzf /tmp/CPANPLUS-0.9003.tar.gz
83     # tar xzf /tmp/CPANPLUS-Dist-Gentoo-0.09.tar.gz
84
85 Set up environment variables so that the toolchain is temporarily available :
86
87     # export OLDPATH=$PATH
88     # export PATH=/root/CPANPLUS-0.9003/bin:$PATH
89     # export PERL5LIB=/root/CPANPLUS-Dist-Gentoo-0.09/blib/lib:/root/CPANPLUS-0.9003/lib:/root/CPANPLUS-0.9003/inc/bundle
90
91 Make sure you don't have an old C<.cpanplus> configuration visible :
92
93     # [ -d /root/.cpanplus ] && mv /root/.cpanplus{,.bak}
94
95 Bootstrap L<CPANPLUS> :
96
97     # cd /root/CPANPLUS-Dist-Gentoo-0.09
98     # samples/g-cpanp CPANPLUS
99
100 Reset the environment :
101
102     # export PATH=$OLDPATH
103     # unset PERL5LIB OLDPATH
104
105 Emerge L<CPANPLUS> with the ebuilds you've just generated :
106
107     # emerge -tv CPANPLUS
108
109 As of september 2009, C<podlators> and C<ExtUtils-MakeMaker> may fail to emerge due to collisions.
110 You can work around this by disabling the C<protect-owned> C<FEATURE> for them :
111
112     # FEATURES="-protect-owned" emerge podlators
113     # FEATURES="-protect-owned" emerge ExtUtils-MakeMaker
114
115 You may need to run each of these commands two times for them to succeed.
116
117 At this point, you can bootstrap L<CPANPLUS::Dist::Gentoo> using the system L<CPANPLUS> :
118
119     # PERL5LIB=/root/CPANPLUS-Dist-Gentoo-0.09/blib/lib samples/g-cpanp CPANPLUS::Dist::Gentoo
120     # emerge -tv CPANPLUS-Dist-Gentoo
121
122 =back
123
124 =head1 METHODS
125
126 This module inherits all the methods from L<CPANPLUS::Dist::Base>.
127 Please refer to its documentation for precise information on what's done at each step.
128
129 =cut
130
131 use constant CATEGORY => 'perl-gcpanp';
132
133 my $overlays;
134 my $default_keywords;
135 my $default_distdir;
136 my $main_portdir;
137
138 my %forced;
139
140 my $unquote = sub {
141  my $s = shift;
142  $s =~ s/^["']*//;
143  $s =~ s/["']*$//;
144  return $s;
145 };
146
147 my $format_available;
148
149 sub format_available {
150  return $format_available if defined $format_available;
151
152  for my $prog (qw/emerge ebuild/) {
153   unless (IPC::Cmd::can_run($prog)) {
154    __PACKAGE__->_abort("$prog is required to write ebuilds");
155    return $format_available = 0;
156   }
157  }
158
159  if (IPC::Cmd->can_capture_buffer) {
160   my $buffers;
161   my ($success, $errmsg) = IPC::Cmd::run(
162    command => [ qw/emerge --info/ ],
163    verbose => 0,
164    buffer  => \$buffers,
165   );
166   if ($success) {
167    if ($buffers =~ /^PORTDIR_OVERLAY=(.*)$/m) {
168     $overlays = [ map Cwd::abs_path($_), split ' ', $unquote->($1) ];
169    }
170    if ($buffers =~ /^ACCEPT_KEYWORDS=(.*)$/m) {
171     $default_keywords = [ split ' ', $unquote->($1) ];
172    }
173    if ($buffers =~ /^DISTDIR=(.*)$/m) {
174     $default_distdir = Cwd::abs_path($unquote->($1));
175    }
176    if ($buffers =~ /^PORTDIR=(.*)$/m) {
177     $main_portdir = Cwd::abs_path($unquote->($1));
178    }
179   } else {
180    __PACKAGE__->_abort($errmsg);
181   }
182  }
183
184  $default_keywords = [ 'x86' ] unless defined $default_keywords;
185  $default_distdir  = '/usr/portage/distfiles' unless defined $default_distdir;
186
187  return $format_available = 1;
188 }
189
190 sub init {
191  my ($self) = @_;
192  my $stat = $self->status;
193  my $conf = $self->parent->parent->configure_object;
194
195  $stat->mk_accessors(qw/name version author distribution desc uri src license
196                         fetched_arch requires
197                         ebuild_name ebuild_version ebuild_dir ebuild_file
198                         portdir_overlay
199                         overlay distdir keywords do_manifest header footer
200                         force verbose/);
201
202  $stat->force($conf->get_conf('force'));
203  $stat->verbose($conf->get_conf('verbose'));
204
205  return 1;
206 }
207
208 sub prepare {
209  my $self = shift;
210  my $mod  = $self->parent;
211  my $stat = $self->status;
212  my $int  = $mod->parent;
213  my $conf = $int->configure_object;
214
215  my %opts = @_;
216
217  my $OK   = sub { $stat->prepared(1); 1 };
218  my $FAIL = sub { $stat->prepared(0); $self->_abort(@_) if @_; 0 };
219  my $SKIP = sub { $stat->prepared(1); $stat->created(1); $self->_skip(@_) if @_; 1 };
220
221  my $keywords = delete $opts{keywords};
222  if (defined $keywords) {
223   $keywords = [ split ' ', $keywords ];
224  } else {
225   $keywords = $default_keywords;
226  }
227  $stat->keywords($keywords);
228
229  my $manifest = delete $opts{manifest};
230  $manifest = 1 unless defined $manifest;
231  $manifest = 0 if $manifest =~ /^\s*no?\s*$/i;
232  $stat->do_manifest($manifest);
233
234  my $header = delete $opts{header};
235  if (defined $header) {
236   1 while chomp $header;
237   $header .= "\n\n";
238  } else {
239   my $year = (localtime)[5] + 1900;
240   $header = <<"  DEF_HEADER";
241 # Copyright 1999-$year Gentoo Foundation
242 # Distributed under the terms of the GNU General Public License v2
243 # \$Header: \$
244   DEF_HEADER
245  }
246  $stat->header($header);
247
248  my $footer = delete $opts{footer};
249  if (defined $footer) {
250   $footer = "\n" . $footer;
251  } else {
252   $footer = '';
253  }
254  $stat->footer($footer);
255
256  my $overlay = delete $opts{overlay};
257  $overlay = (defined $overlay) ? Cwd::abs_path($overlay) : '/usr/local/portage';
258  $stat->overlay($overlay);
259
260  my $distdir = delete $opts{distdir};
261  $distdir = (defined $distdir) ? Cwd::abs_path($distdir) : $default_distdir;
262  $stat->distdir($distdir);
263
264  return $FAIL->("distdir isn't writable") if $stat->do_manifest && !-w $distdir;
265
266  $stat->fetched_arch($mod->status->fetch);
267
268  my $cur = File::Spec->curdir();
269  my $portdir_overlay;
270  for (@$overlays) {
271   if ($_ eq $overlay or File::Spec->abs2rel($overlay, $_) eq $cur) {
272    $portdir_overlay = [ @$overlays ];
273    last;
274   }
275  }
276  $portdir_overlay = [ @$overlays, $overlay ] unless $portdir_overlay;
277  $stat->portdir_overlay($portdir_overlay);
278
279  my $name = $mod->package_name;
280  $stat->name($name);
281
282  my $version = $mod->package_version;
283  $stat->version($version);
284
285  my $author = $mod->author->cpanid;
286  $stat->author($author);
287
288  $stat->distribution($name . '-' . $version);
289
290  $stat->ebuild_version(CPANPLUS::Dist::Gentoo::Maps::version_c2g($version));
291
292  $stat->ebuild_name(CPANPLUS::Dist::Gentoo::Maps::name_c2g($name));
293
294  $stat->ebuild_dir(File::Spec->catdir(
295   $stat->overlay,
296   CATEGORY,
297   $stat->ebuild_name,
298  ));
299
300  my $file = File::Spec->catfile(
301   $stat->ebuild_dir,
302   $stat->ebuild_name . '-' . $stat->ebuild_version . '.ebuild',
303  );
304  $stat->ebuild_file($file);
305
306  if ($stat->force) {
307   # Always generate an ebuild in our category when forcing
308   if ($forced{$file}) {
309    $stat->dist($file);
310    return $SKIP->('Ebuild already forced for', $stat->distribution);
311   }
312   ++$forced{$file};
313   if (-e $file) {
314    unless (-w $file) {
315     $stat->dist($file);
316     return $SKIP->("Can't force rewriting of $file");
317    }
318    1 while unlink $file;
319   }
320  } else {
321   if (my $atom = $self->_cpan2portage($name, $version)) {
322    $stat->dist($atom->ebuild);
323    return $SKIP->('Ebuild already generated for', $stat->distribution);
324   }
325  }
326
327  $stat->prepared(0);
328
329  $self->SUPER::prepare(@_);
330
331  return $FAIL->() unless $stat->prepared;
332
333  my $desc = $mod->description;
334  ($desc = $name) =~ s/-+/::/g unless $desc;
335  $stat->desc($desc);
336
337  $stat->uri('http://search.cpan.org/dist/' . $name);
338
339  $author =~ /^(.)(.)/ or return $FAIL->('Wrong author name');
340  $stat->src("mirror://cpan/modules/by-authors/id/$1/$1$2/$author/" . $mod->package);
341
342  $stat->license($self->intuit_license);
343
344  my $prereqs = $mod->status->requires;
345  my @requires;
346  for my $prereq (sort keys %$prereqs) {
347   next if $prereq =~ /^perl(?:-|\z)/;
348   my $obj = $int->module_tree($prereq);
349   next unless $obj; # Not in the module tree (e.g. Config)
350   next if $obj->package_is_perl_core;
351   {
352    my $version;
353    if ($prereqs->{$prereq}) {
354     if ($obj->installed_version && $obj->installed_version < $obj->version) {
355      $version = $obj->installed_version;
356     } else {
357      $version = $obj->package_version;
358     }
359    }
360    push @requires, [ $obj->package_name, $version ];
361   }
362  }
363  $stat->requires(\@requires);
364
365  return $OK->();
366 }
367
368 =head2 C<intuit_license>
369
370 Returns an array reference to a list of Gentoo licences identifiers under which the current distribution is released.
371
372 =cut
373
374 my %dslip_license = (
375  p => 'perl',
376  g => 'gpl',
377  l => 'lgpl',
378  b => 'bsd',
379  a => 'artistic',
380  2 => 'artistic_2',
381 );
382
383 sub intuit_license {
384  my $self = shift;
385  my $mod  = $self->parent;
386
387  my $dslip = $mod->dslip;
388  if (defined $dslip and $dslip =~ /\S{4}(\S)/) {
389   my @licenses = CPANPLUS::Dist::Gentoo::Maps::license_c2g($dslip_license{$1});
390   return \@licenses if @licenses;
391  }
392
393  my $extract_dir = $mod->status->extract;
394
395  for my $meta_file (qw/META.json META.yml/) {
396   my $meta = eval {
397    Parse::CPAN::Meta::LoadFile(File::Spec->catdir(
398     $extract_dir,
399     $meta_file,
400    ));
401   } or next;
402   my $license = $meta->{license};
403   if (defined $license) {
404    my @licenses = CPANPLUS::Dist::Gentoo::Maps::license_c2g($license);
405    return \@licenses if @licenses;
406   }
407  }
408
409  return [ CPANPLUS::Dist::Gentoo::Maps::license_c2g('perl') ];
410 }
411
412 sub create {
413  my $self = shift;
414  my $stat = $self->status;
415
416  my $file;
417
418  my $OK   = sub {
419   $stat->created(1);
420   $stat->dist($file) if defined $file;
421   1;
422  };
423
424  my $FAIL = sub {
425   $stat->created(0);
426   $stat->dist(undef);
427   $self->_abort(@_) if @_;
428   if (defined $file and -f $file) {
429    1 while unlink $file;
430   }
431   0;
432  };
433
434  unless ($stat->prepared) {
435   return $FAIL->(
436    'Can\'t create', $stat->distribution, 'since it was never prepared'
437   );
438  }
439
440  if ($stat->created) {
441   $self->_skip($stat->distribution, 'was already created');
442   $file = $stat->dist; # Keep the existing one.
443   return $OK->();
444  }
445
446  my $dir = $stat->ebuild_dir;
447  unless (-d $dir) {
448   eval { File::Path::mkpath($dir) };
449   return $FAIL->("mkpath($dir): $@") if $@;
450  }
451
452  $file = $stat->ebuild_file;
453
454  # Create a placeholder ebuild to prevent recursion with circular dependencies.
455  {
456   open my $eb, '>', $file or return $FAIL->("open($file): $!");
457   print $eb "PLACEHOLDER\n";
458  }
459
460  $stat->created(0);
461  $stat->dist(undef);
462
463  $self->SUPER::create(@_);
464
465  return $FAIL->() unless $stat->created;
466
467  {
468   open my $eb, '>', $file or return $FAIL->("open($file): $!");
469   my $source = $self->ebuild_source;
470   return $FAIL->() unless defined $source;
471   print $eb $source;
472  }
473
474  return $FAIL->() if $stat->do_manifest and not $self->update_manifest;
475
476  return $OK->();
477 }
478
479 =head2 C<update_manifest>
480
481 Updates the F<Manifest> file for the ebuild associated to the current dist object.
482
483 =cut
484
485 sub update_manifest {
486  my $self = shift;
487  my $stat = $self->status;
488
489  my $file = $stat->ebuild_file;
490  unless (defined $file and -e $file) {
491   return $self->_abort('The ebuild file is invalid or does not exist');
492  }
493
494  unless (File::Copy::copy($stat->fetched_arch => $stat->distdir)) {
495   return $self->_abort("Couldn\'t copy the distribution file to distdir ($!)");
496  }
497
498  $self->_notify('Adding Manifest entry for', $stat->distribution);
499
500  return $self->_run([ 'ebuild', $file, 'manifest' ], 0);
501 }
502
503 =head2 C<ebuild_source>
504
505 Returns the source of the ebuild for the current dist object, or C<undef> when one of the dependencies couldn't be mapped to an existing ebuild.
506
507 =cut
508
509 sub ebuild_source {
510  my $self = shift;
511  my $stat = $self->status;
512
513  # We must resolve the deps now and not inside prepare because _cpan2portage
514  # has to see the ebuilds already generated for the dependencies of the current
515  # dist.
516  my @requires;
517  for (@{$stat->requires}) {
518   my $atom = $self->_cpan2portage(@$_);
519   unless (defined $atom) {
520    $self->_abort(
521     "Couldn't find an appropriate ebuild for $_->[0] in the portage tree"
522    );
523    return;
524   }
525   push @requires, $atom;
526  }
527
528  my $perl = CPANPLUS::Dist::Gentoo::Atom->new(
529   category => 'dev-lang',
530   name     => 'perl',
531  );
532  @requires = CPANPLUS::Dist::Gentoo::Atom->fold($perl, @requires);
533
534  my $d = $stat->header;
535  $d   .= "# Generated by CPANPLUS::Dist::Gentoo version $VERSION\n\n";
536  $d   .= 'MODULE_AUTHOR="' . $stat->author . "\"\ninherit perl-module\n\n";
537  $d   .= 'S="${WORKDIR}/' . $stat->distribution . "\"\n";
538  $d   .= 'DESCRIPTION="' . $stat->desc . "\"\n";
539  $d   .= 'HOMEPAGE="' . $stat->uri . "\"\n";
540  $d   .= 'SRC_URI="' . $stat->src . "\"\n";
541  $d   .= "SLOT=\"0\"\n";
542  $d   .= 'LICENSE="|| ( ' . join(' ', sort @{$stat->license}) . " )\"\n";
543  $d   .= 'KEYWORDS="' . join(' ', sort @{$stat->keywords}) . "\"\n";
544  $d   .= 'RDEPEND="' . join("\n", sort @requires) . "\"\n";
545  $d   .= "DEPEND=\"\${RDEPEND}\"\n";
546  $d   .= "SRC_TEST=\"do\"\n";
547  $d   .= $stat->footer;
548
549  return $d;
550 }
551
552 sub _cpan2portage {
553  my ($self, $name, $version) = @_;
554
555  $name    = CPANPLUS::Dist::Gentoo::Maps::name_c2g($name);
556  $version = CPANPLUS::Dist::Gentoo::Maps::version_c2g($version);
557
558  my @portdirs = ($main_portdir, @{$self->status->portdir_overlay});
559
560  for my $category (qw/virtual perl-core dev-perl perl-gcpan/, CATEGORY) {
561   my $name = ($category eq 'virtual' ? 'perl-' : '') . $name;
562
563   for my $portdir (@portdirs) {
564    my @ebuilds = glob File::Spec->catfile(
565     $portdir,
566     $category,
567     $name,
568     "$name-*.ebuild",
569    ) or next;
570
571    my $last = reduce { $a < $b ? $b : $a } # handles overloading
572                map CPANPLUS::Dist::Gentoo::Atom->new_from_ebuild($_),
573                 @ebuilds;
574    next if defined $version and $last < $version;
575
576    return CPANPLUS::Dist::Gentoo::Atom->new(
577     category => $last->category,
578     name     => $last->name,
579     (defined $version ? (version => $version, range => '>=') : ()),
580     ebuild   => $last->ebuild,
581    );
582   }
583
584  }
585
586  return;
587 }
588
589 sub install {
590  my $self = shift;
591  my $stat = $self->status;
592  my $conf = $self->parent->parent->configure_object;
593
594  my $sudo = $conf->get_program('sudo');
595  my @cmd = ('emerge', '=' . $stat->ebuild_name . '-' . $stat->ebuild_version);
596  unshift @cmd, $sudo if $sudo;
597
598  my $success = $self->_run(\@cmd, 1);
599  $stat->installed($success);
600
601  return $success;
602 }
603
604 sub uninstall {
605  my $self = shift;
606  my $stat = $self->status;
607  my $conf = $self->parent->parent->configure_object;
608
609  my $sudo = $conf->get_program('sudo');
610  my @cmd = ('emerge', '-C', '=' . $stat->ebuild_name . '-' . $stat->ebuild_version);
611  unshift @cmd, $sudo if $sudo;
612
613  my $success = $self->_run(\@cmd, 1);
614  $stat->uninstalled($success);
615
616  return $success;
617 }
618
619 sub _run {
620  my ($self, $cmd, $verbose) = @_;
621  my $stat = $self->status;
622
623  my ($success, $errmsg, $output) = do {
624   local $ENV{PORTDIR_OVERLAY}     = join ' ', @{$stat->portdir_overlay};
625   local $ENV{PORTAGE_RO_DISTDIRS} = $stat->distdir;
626   IPC::Cmd::run(
627    command => $cmd,
628    verbose => $verbose,
629   );
630  };
631
632  unless ($success) {
633   $self->_abort($errmsg);
634   if (not $verbose and defined $output and $stat->verbose) {
635    my $msg = join '', @$output;
636    1 while chomp $msg;
637    CPANPLUS::Error::error($msg);
638   }
639  }
640
641  return $success;
642 }
643
644 sub _abort {
645  my $self = shift;
646
647  CPANPLUS::Error::error("@_ -- aborting");
648
649  return 0;
650 }
651
652 sub _notify {
653  my $self = shift;
654
655  CPANPLUS::Error::msg("@_");
656
657  return 1;
658 }
659
660 sub _skip { shift->_notify(@_, '-- skipping') }
661
662 =head1 DEPENDENCIES
663
664 Gentoo (L<http://gentoo.org>).
665
666 L<CPANPLUS>, L<IPC::Cmd> (core modules since 5.9.5), L<Parse::CPAN::Meta> (since 5.10.1).
667
668 L<Cwd>, L<Carp> (since perl 5), L<File::Path> (5.001), L<File::Copy> (5.002), L<File::Spec> (5.00405), L<List::Util> (5.007003).
669
670 =head1 SEE ALSO
671
672 L<cpan2dist>.
673
674 L<CPANPLUS::Dist::Base>, L<CPANPLUS::Dist::Deb>, L<CPANPLUS::Dist::Mdv>.
675
676 =head1 AUTHOR
677
678 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
679
680 You can contact me by mail or on C<irc.perl.org> (vincent).
681
682 =head1 BUGS
683
684 Please report any bugs or feature requests to C<bug-cpanplus-dist-gentoo at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=CPANPLUS-Dist-Gentoo>.
685 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
686
687 =head1 SUPPORT
688
689 You can find documentation for this module with the perldoc command.
690
691     perldoc CPANPLUS::Dist::Gentoo
692
693 =head1 ACKNOWLEDGEMENTS
694
695 The module was inspired by L<CPANPLUS::Dist::Deb> and L<CPANPLUS::Dist::Mdv>.
696
697 Kent Fredric, for testing and suggesting improvements.
698
699 =head1 COPYRIGHT & LICENSE
700
701 Copyright 2008,2009,2010 Vincent Pit, all rights reserved.
702
703 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
704
705 =cut
706
707 1; # End of CPANPLUS::Dist::Gentoo