package Sepia::CPAN; use CPAN (); sub init { CPAN::HandleConfig->load; CPAN::Shell::setup_output; CPAN::Index->reload; } sub interesting_parts { my $mod = shift; # XXX: stupid CPAN.pm functions die for some modules... +{ map { $_ => scalar eval { $mod->$_ } } qw(id cpan_version inst_version fullname cpan_file)}; } # Only list the "root" module of each package, meaning either (1) the # module matching the dist name or (2) the module with the shortest # name, whichever comes first. # XXX: this is hacky. sub group_by_dist { my %h; for (@_) { my $cf = $_->{cpan_file}; if (!exists $h{$cf}) { $h{$_->{cpan_file}} = $_; } else { (my $tmp = $cf) =~ s/-/::/g; if ($tmp =~ /^\Q$h{$cf}{id}\E/) { next; # already perfect } elsif ($tmp =~ /^\Q$_->{id}\E/) { $h{$cf} = $_; # perfect } # elsif (length $h{$cf}{id} > length $_->{id}) { # $h{$cf} = $_; # short, at least... # } } } sort { $a->{id} cmp $b->{id} } values %h; } sub _list { CPAN::Shell->expand('Module', shift || '/./'); } sub list { group_by_dist map { interesting_parts $_ } _list @_ } sub _ls { my $want = shift; grep { # XXX: key to test in this order, because inst_file is slow. $_->userid eq $want } CPAN::Shell->expand('Module', '/./') } sub ls { group_by_dist map { interesting_parts $_ } _ls @_ } sub _desc { my $pat = qr/$_[0]/i; grep { $_->description && ($_->description =~ /$pat/ || $_->id =~ /$pat/) } CPAN::Shell->expand('Module', '/./'); } sub desc { group_by_dist map { interesting_parts $_ } _desc @_; } sub outdated { grep !$_->uptodate, list @_; } ## stolen from CPAN::Shell... sub readme { my $dist = CPAN::Shell->expand('Module', shift); return unless $dist; my $wantfile = shift; $dist = $dist->cpan_file; # my ($dist) = $self->id; my ($sans, $suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/; my ($local_file); my ($local_wanted) = File::Spec->catfile( $CPAN::Config->{keep_source_where}, "authors", "id", split(/\//,"$sans.readme")); $local_file = CPAN::FTP->localize("authors/id/$sans.readme", $local_wanted); ## Return filename rather than contents to avoid Elisp reader issues... if ($wantfile) { $local_file; } else { local (*IN, $/); open IN, $local_wanted; my $ret = ; close IN; $ret; } } sub perldoc { eval q{ use LWP::Simple; }; if ($@) { print STDERR "Can't get perldocs: LWP::Simple not installed.\n"; "Can't get perldocs: LWP::Simple not installed.\n"; } else { *perldoc = sub { get($CPAN::Defaultdocs . shift) }; goto &perldoc; } } sub install { my $dist = CPAN::Shell->expand('Module', shift); $dist->install if $dist; } # Based on CPAN::Shell::_u_r_common sub _recommend { my $pat = shift || '/./'; my (@result, %seen, %need); $version_undefs = $version_zeroes = 0; for my $module (CPAN::Shell->expand('Module',$pat)) { my $file = $module->cpan_file; next unless defined $file && $module->inst_file; $file =~ s!^./../!!; my $latest = $module->cpan_version; my $have = $module->inst_version; local ($^W) = 0; next unless CPAN::Version->vgt($latest, $have); push @result, $module; next if $seen{$file}++; $need{$module->id}++; } @result; } sub recommend { group_by_dist map { interesting_parts $_ } _recommend @_; } 1;