2 # vim:ts=4:shiftwidth=4:expandtab
6 App::RetroPAN - Makes a historic minicpan E<9203>
12 my ($author, $dist_name, $url) = find_module_on_date("2011-01-01T00:00:00", "Moose");
16 Uses the MetaCPAN API to find releases made prior to a given date to
17 satisfy your modules' dependencies.
31 This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
35 Dave Lambley <dlambley@cpan.org>
44 use List
::Util qw
/ uniq /;
46 use OrePAN2
::Injector
;
49 use Cpanel
::JSON
::XS qw
/ encode_json decode_json /;
53 my $ua = LWP
::UserAgent
->new( keep_alive
=> 2, agent
=> "retropan/$VERSION" );
55 sub find_module_dependencies
{
79 my $req = HTTP
::Request
->new( POST
=> 'https://fastapi.metacpan.org/v1/release/_search', [
80 "Content-Type" => "text/json",
81 "Accept" => "text/json"
84 my $res = $ua->request($req);
85 die $res->status_line if !$res->is_success;
86 my $data = decode_json
($res->decoded_content);
87 my $hit = $data->{hits
}->{hits
}->[0];
89 warn "could not find $au/$dist";
94 grep { !Module
::CoreList
::is_core
($_) }
96 map { $_->{module
} } @
{ $hit->{_source
}->{dependency
} };
100 sub find_module_on_date
{
101 my ($module, $before) = @_;
103 return if Module
::CoreList
::is_core
($module);
105 # We prefer authorized modules, but can fall back to unauthorized if none
108 "size" => 30, # TODO, keep search open.
110 { "module.authorized" => "desc" },
111 { "version_numified" => "desc" },
119 "module.name" => $module,
124 "maturity" => "released",
128 "range" => { "date" => {"lt" => $before }}
135 my $req = HTTP
::Request
->new( POST
=> 'https://fastapi.metacpan.org/v1/module/_search', [
136 "Content-Type" => "text/json",
137 "Accept" => "text/json"
138 ], encode_json
($q) );
140 my $res = $ua->request($req);
141 die $res->status_line if !$res->is_success;
142 my $data = decode_json
($res->decoded_content);
151 # Some distributions re-release existing modules outside their own
152 # distribution, eg., perl-5.005-minimal-bin-0-arm-linux
153 # We therefore iterate through all modules returned to find the newest
155 foreach my $hit (@
{ $data->{hits
}->{hits
} }) {
156 foreach my $mod (@
{ $hit->{_source
}->{module
} }) {
157 if (($authorized ?
$mod->{authorized
} : 1) && $mod->{name
} eq $module && $mod->{version_numified
} > $version) {
158 $author = $hit->{_source
}->{author
};
159 $release = $hit->{_source
}->{release
};
160 $url = $hit->{_source
}->{download_url
};
161 $version = $mod->{version_numified
};
162 $authorized = $mod->{authorized
};
168 if (!defined $release) {
169 warn "could not find $module before $before";
173 return ($author, $release, $url);
176 sub find_deps_on_date
{
177 my ($before, @modules) = @_;
184 my $mod = pop @modules;
185 next if $done_modules{$mod};
187 my ($au, $dist, $url) = find_module_on_date
($mod, $before);
188 $done_modules{$mod} = 1;
189 next if !defined($au) || !defined($dist);
190 $dist_to_url{"$au/$dist"} = $url;
192 push @modules, find_module_dependencies
($au, $dist);
193 unshift @dists_required, "$au/$dist";
197 [uniq
@dists_required],
203 my ($localdir, $dists_required, $dist_to_url) = @_;
205 my $injector = OrePAN2
::Injector
->new(
206 directory
=> $localdir,
210 foreach my $d (@
{ $dists_required }) {
211 my ($author, $dist) = split(/\//, $d, 2);
213 $dist_to_url->{$d} // die,
221 my $orepan = OrePAN2
::Indexer
->new(
222 directory
=> $localdir,