76 lines
1.5 KiB
Perl
76 lines
1.5 KiB
Perl
package Cpan;
|
|
|
|
use Net::Async::HTTP;
|
|
use Future;
|
|
use v5.20;
|
|
use strict;
|
|
use warnings;
|
|
use Data::Dumper;
|
|
|
|
my $http = Net::Async::HTTP->new();
|
|
my $loop = IO::Async::Loop->new();
|
|
$loop->add($http);
|
|
|
|
{
|
|
my $httpfuture;
|
|
my $parsefuture;
|
|
my $index;
|
|
my $rawindex;
|
|
|
|
# shortcut wrapper
|
|
sub f {$loop->new_future(@_)}
|
|
|
|
# I want this fully private to these subs.
|
|
my $fetch_index = sub {
|
|
return $httpfuture if $httpfuture;
|
|
my $url = "http://www.cpan.org/modules/02packages.details.txt";
|
|
$httpfuture = $http->GET($url);
|
|
|
|
$httpfuture->on_done(sub {
|
|
my $resp = shift;
|
|
die "Failed to fetch cpan index" if ($resp->code ne 200);
|
|
|
|
$rawindex = $resp->decoded_content();
|
|
})->on_fail(sub {die "Failed to fetch cpan index"});
|
|
return $httpfuture;
|
|
};
|
|
|
|
sub raw_index {
|
|
return f()->done($rawindex) if ($rawindex);
|
|
|
|
my $f = $fetch_index->();
|
|
my $nf = f();
|
|
|
|
$f->on_done(sub {$nf->done($rawindex)});
|
|
return $nf;
|
|
}
|
|
|
|
sub index {
|
|
return f()->done($index) if ($index);
|
|
|
|
my $f = raw_index();
|
|
|
|
$index = {};
|
|
|
|
my $nf = f();
|
|
$f->on_done(sub {
|
|
my $rawindex = shift();
|
|
|
|
$rawindex =~ s/\A.*?\r?\n\r?\n//s; # cut off the header
|
|
|
|
for my $line (split /\r?\n/, $rawindex) {
|
|
if ($line =~ /^(?<module>\S+)\s+(?<version>\S+)\s+(?<dist>\S+)\s*$/) {
|
|
$index->{$+{module}} = {version => $+{version}, dist => $+{dist}};
|
|
} else {
|
|
warn "Got invalid line, $line";
|
|
}
|
|
};
|
|
|
|
$nf->done($index);
|
|
});
|
|
|
|
return $nf
|
|
}
|
|
}
|
|
|
|
1;
|