line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ABSTRACT: Find a package among CPAN-like repositories |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package Package::Locator; |
4
|
|
|
|
|
|
|
|
5
|
4
|
|
|
4
|
|
499546
|
use Moose; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
use MooseX::MarkAsMethods (autoclean => 1); |
7
|
|
|
|
|
|
|
use MooseX::Types::Path::Class; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use Carp; |
10
|
|
|
|
|
|
|
use File::Temp; |
11
|
|
|
|
|
|
|
use Path::Class; |
12
|
|
|
|
|
|
|
use LWP::UserAgent; |
13
|
|
|
|
|
|
|
use CPAN::DistnameInfo; |
14
|
|
|
|
|
|
|
use URI; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use Package::Locator::Index; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use version; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our $VERSION = '0.010'; # VERSION |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
has repository_urls => ( |
29
|
|
|
|
|
|
|
is => 'ro', |
30
|
|
|
|
|
|
|
isa => 'ArrayRef[URI]', |
31
|
|
|
|
|
|
|
auto_deref => 1, |
32
|
|
|
|
|
|
|
default => sub { [URI->new('http://cpan.perl.org')] }, |
33
|
|
|
|
|
|
|
); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
has user_agent => ( |
39
|
|
|
|
|
|
|
is => 'ro', |
40
|
|
|
|
|
|
|
isa => 'LWP::UserAgent', |
41
|
|
|
|
|
|
|
builder => '_build_user_agent', |
42
|
|
|
|
|
|
|
); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub _build_user_agent { |
45
|
|
|
|
|
|
|
my ($self) = @_; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my $agent = sprintf "%s/%s", ref $self, $self->VERSION || 'UNKNOWN'; |
48
|
|
|
|
|
|
|
return LWP::UserAgent->new(agent => $agent, env_proxy => 1, keep_alive => 5); |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
has cache_dir => ( |
55
|
|
|
|
|
|
|
is => 'ro', |
56
|
|
|
|
|
|
|
isa => 'Path::Class::Dir', |
57
|
|
|
|
|
|
|
default => sub { Path::Class::Dir->new( File::Temp::tempdir(CLEANUP => 1) ) }, |
58
|
|
|
|
|
|
|
coerce => 1, |
59
|
|
|
|
|
|
|
); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
has force => ( |
65
|
|
|
|
|
|
|
is => 'ro', |
66
|
|
|
|
|
|
|
isa => 'Bool', |
67
|
|
|
|
|
|
|
default => 0, |
68
|
|
|
|
|
|
|
); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
has indexes => ( |
74
|
|
|
|
|
|
|
is => 'ro', |
75
|
|
|
|
|
|
|
isa => 'ArrayRef[Package::Locator::Index]', |
76
|
|
|
|
|
|
|
auto_deref => 1, |
77
|
|
|
|
|
|
|
lazy_build => 1, |
78
|
|
|
|
|
|
|
init_arg => undef, |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub _build_indexes { |
85
|
|
|
|
|
|
|
my ($self) = @_; |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
my @indexes = map { Package::Locator::Index->new( force => $self->force(), |
88
|
|
|
|
|
|
|
cache_dir => $self->cache_dir(), |
89
|
|
|
|
|
|
|
user_agent => $self->user_agent(), |
90
|
|
|
|
|
|
|
repository_url => $_ ) |
91
|
|
|
|
|
|
|
} $self->repository_urls(); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
return \@indexes; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub locate { |
100
|
|
|
|
|
|
|
my ($self, %args) = @_; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
$self->_validate_locate_args(%args); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
if ($args{package}) { |
105
|
|
|
|
|
|
|
my $package = $args{package}; |
106
|
|
|
|
|
|
|
my $version = $args{version} || 0; |
107
|
|
|
|
|
|
|
my $latest = $args{latest} || 0; |
108
|
|
|
|
|
|
|
return $self->_locate_package($package, $version, $latest); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
else { |
111
|
|
|
|
|
|
|
my $dist = $args{distribution}; |
112
|
|
|
|
|
|
|
return $self->_locate_dist($dist); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub _validate_locate_args { |
119
|
|
|
|
|
|
|
my ($self, %args) = @_; |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
croak 'Cannot specify latest and distribution together' |
122
|
|
|
|
|
|
|
if $args{distribution} and $args{latest}; |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
croak 'Cannot specify version and distribution together' |
125
|
|
|
|
|
|
|
if $args{distribution} and $args{version}; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
croak 'Cannot specify package and distribution together' |
128
|
|
|
|
|
|
|
if $args{distribution} and $args{package}; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
croak 'Must specify package or distribution' |
131
|
|
|
|
|
|
|
if not ( $args{distribution} or $args{package} ); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
return 1; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub _locate_package { |
139
|
|
|
|
|
|
|
my ($self, $package, $version, $latest) = @_; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
my $wanted_version = version->parse($version); |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
my ($latest_found_package, $found_in_index); |
144
|
|
|
|
|
|
|
for my $index ( $self->indexes() ) { |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
my $found_package = $index->packages->{$package}; |
147
|
|
|
|
|
|
|
next if not $found_package; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
my $found_package_version = version->parse( $found_package->{version} ); |
150
|
|
|
|
|
|
|
next if $found_package_version < $wanted_version; |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
$found_in_index ||= $index; |
153
|
|
|
|
|
|
|
$latest_found_package ||= $found_package; |
154
|
|
|
|
|
|
|
last unless $latest; |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
($found_in_index, $latest_found_package) = ($index, $found_package) |
157
|
|
|
|
|
|
|
if $self->__compare_packages($found_package, $latest_found_package) == 1; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
if ($latest_found_package) { |
162
|
|
|
|
|
|
|
my $base_url = $found_in_index->repository_url(); |
163
|
|
|
|
|
|
|
my $latest_dist_path = $latest_found_package->{distribution}; |
164
|
|
|
|
|
|
|
return URI->new( "$base_url/authors/id/" . $latest_dist_path ); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
return; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub _locate_dist { |
173
|
|
|
|
|
|
|
my ($self, $dist_path) = @_; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
for my $index ( $self->indexes ) { |
176
|
|
|
|
|
|
|
my $base_url = $index->repository_url(); |
177
|
|
|
|
|
|
|
my $dist_url = URI->new("$base_url/authors/id/$dist_path"); |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
return $dist_url if $index->distributions->{$dist_path}; |
180
|
|
|
|
|
|
|
return $dist_url if $self->user_agent->head($dist_url)->is_success; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
return; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub __compare_packages { |
190
|
|
|
|
|
|
|
my ($self, $pkg_a, $pkg_b) = @_; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
my $pkg_a_version = $self->__versionize( $pkg_a->{version} ); |
193
|
|
|
|
|
|
|
my $pkg_b_version = $self->__versionize( $pkg_b->{version} ); |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# TODO: compare dist mtimes (but they are on the server!) |
196
|
|
|
|
|
|
|
return $pkg_a_version <=> $pkg_b_version; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub __versionize { |
202
|
|
|
|
|
|
|
my ($self, $version) = @_; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
my $v = eval { version->parse($version) }; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
return defined $v ? $v : version->new(0); |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub clear_cache { |
213
|
|
|
|
|
|
|
my ($self) = @_; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
for my $index ( $self->indexes() ) { |
216
|
|
|
|
|
|
|
$index->index_file->remove(); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
$self->clear_indexes(); |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
return $self; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
1; |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
__END__ |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=pod |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=for :stopwords Jeffrey Ryan Thalhammer Imaginative Software Systems cpan testmatrix url |
237
|
|
|
|
|
|
|
annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata |
238
|
|
|
|
|
|
|
placeholders metacpan |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head1 NAME |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Package::Locator - Find a package among CPAN-like repositories |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head1 VERSION |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
version 0.010 |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=head1 SYNOPSIS |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
use Package::Locator; |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Basic search... |
253
|
|
|
|
|
|
|
my $locator = Package::Locator->new(); |
254
|
|
|
|
|
|
|
my $url = locator->locate( package => 'Test::More' ); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# Search for first within multiple repositories: |
257
|
|
|
|
|
|
|
my $repos = [ qw(http://cpan.pair.com http://my.company.com/DPAN) ]; |
258
|
|
|
|
|
|
|
my $locator = Package::Locator->new( repository_urls => $repos ); |
259
|
|
|
|
|
|
|
my $url = locator->locate( package => 'Test::More' ); |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# Search for first where version >= 0.34: |
262
|
|
|
|
|
|
|
my $repos = [ qw(http://cpan.pair.com http://my.company.com/DPAN) ]; |
263
|
|
|
|
|
|
|
my $locator = Package::Locator->new( repository_urls => $repos ); |
264
|
|
|
|
|
|
|
my $url = locator->locate( package => 'Test::More' version => 0.34); |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# Search for latest where version >= 0.34: |
267
|
|
|
|
|
|
|
my $repos = [ qw(http://cpan.pair.com http://my.company.com/DPAN) ]; |
268
|
|
|
|
|
|
|
my $locator = Package::Locator->new( repository_urls => $repos ); |
269
|
|
|
|
|
|
|
my $url = locator->locate( package => 'Test::More' version => 0.34, latest => 1); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# Search for specific dist on multiple repositories...: |
272
|
|
|
|
|
|
|
my $repos = [ qw(http://cpan.pair.com http://my.company.com/DPAN) ]; |
273
|
|
|
|
|
|
|
my $locator = Package::Locator->new( repository_urls => $repos ); |
274
|
|
|
|
|
|
|
my $url = locator->locate( distribution => 'A/AU/AUTHOR/Foo-1.0.tar.gz'); |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=head1 DESCRIPTION |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
L<Package::Locator> attempts to answer the question: "Where can I find |
279
|
|
|
|
|
|
|
a distribution that will provide this package?" The answer is divined |
280
|
|
|
|
|
|
|
by searching the indexes for one or more CPAN-like repositories. If |
281
|
|
|
|
|
|
|
you also provide a specific version number, L<Package::Locator> will |
282
|
|
|
|
|
|
|
attempt to find a distribution with that version of the package, or |
283
|
|
|
|
|
|
|
higher. You can also ask to find the latest version of a package |
284
|
|
|
|
|
|
|
across all the indexes. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
L<Package::Locator> only looks at the index files for each repository, |
287
|
|
|
|
|
|
|
and those indexes only contain information about the latest versions |
288
|
|
|
|
|
|
|
of the packages within that repository. So L<Package::Locator> is not |
289
|
|
|
|
|
|
|
BackPAN magic -- you cannot use it to find precisely which |
290
|
|
|
|
|
|
|
distribution a particular package (or file) came from. For that |
291
|
|
|
|
|
|
|
stuff, see C<"/See Also">. |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head2 new( %attributes ) |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
All the attributes listed below can be passed to the constructor, and |
298
|
|
|
|
|
|
|
retrieved via accessor methods with the same name. All attributes are |
299
|
|
|
|
|
|
|
read-only, and cannot be changed once the object is constructed. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head2 repository_urls => [ qw(http://somewhere http://somewhere.else) ] |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
An array reference containing the base URLs of the repositories you |
306
|
|
|
|
|
|
|
want to search. These are usually CPAN mirrors, but can be any |
307
|
|
|
|
|
|
|
website or local directory that is organized in a CPAN-like structure. |
308
|
|
|
|
|
|
|
For each request, repositories are searched in the order you specified |
309
|
|
|
|
|
|
|
them here. This defaults to http://cpan.perl.org. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=head2 user_agent => $user_agent_obj |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
The L<LWP::UserAgent> object that will fetch index files. If you do |
314
|
|
|
|
|
|
|
not provide a user agent, then a default one will be constructed for |
315
|
|
|
|
|
|
|
you. |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
=head2 cache_dir => '/some/directory/path' |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
The path (as a string or L<Path::Class::Dir> object) to a directory |
320
|
|
|
|
|
|
|
where the index file will be cached. If the directory does not exist, |
321
|
|
|
|
|
|
|
it will be created for you. If you do not specify a cache directory, |
322
|
|
|
|
|
|
|
then a temporary directory will be used. The temporary directory will |
323
|
|
|
|
|
|
|
be deleted when your application terminates. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=head2 force => $boolean |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
Causes any cached index files to be removed, thus forcing a new one to |
328
|
|
|
|
|
|
|
be downloaded when the object is constructed. This only has effect if |
329
|
|
|
|
|
|
|
you specified the C<cache_dir> attribute. The default is false. |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=head1 METHODS |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=head2 indexes() |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Returns a list of L<Package::Locator::Index> objects representing the |
336
|
|
|
|
|
|
|
indexes of each of the repositories. The indexes are only populated |
337
|
|
|
|
|
|
|
on-demand when the C<locate> method is called. The order of the |
338
|
|
|
|
|
|
|
indexes is the same as the order of the repositories defined by the |
339
|
|
|
|
|
|
|
C<repository_urls> attribute. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=head2 locate( package => 'Foo::Bar' ) |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=head2 locate( package => 'Foo::Bar', latest => 1 ) |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head2 locate( package => 'Foo::Bar', version => '1.2') |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head2 locate( package => 'Foo::Bar', version => '1.2', latest => 1 ) |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head2 locate ( distribution => 'A/AU/AUTHOR/Foo-Bar-1.0.tar.gz' ) |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
Given the name of a package, searches all the repository indexes and |
352
|
|
|
|
|
|
|
returns the URL to a distribution containing that requested package, |
353
|
|
|
|
|
|
|
or the distribution you requested. |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
If you also specify a C<version>, then you'll always get a |
356
|
|
|
|
|
|
|
distribution that contains that version of the package or higher. If |
357
|
|
|
|
|
|
|
you also specify C<latest> then you'll always get the distribution |
358
|
|
|
|
|
|
|
that contains the latest version of the package that can be found in |
359
|
|
|
|
|
|
|
all the indexes. Otherwise you'll just get the first distribution we |
360
|
|
|
|
|
|
|
can find that satisfies your request. |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
If you give a distribution path instead, then you'll just get back the |
363
|
|
|
|
|
|
|
URL to the first distribution we find at that path in any of the |
364
|
|
|
|
|
|
|
repository indexes. |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
If neither the package nor the distribution path can be found in any |
367
|
|
|
|
|
|
|
of the indexes, returns undef. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head2 clear_cache() |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
Deletes the cached index files. Any subsequent calls to the C<locate> |
372
|
|
|
|
|
|
|
method will cause the index files to be fetched anew. |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=head1 MOTIVATION |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
The L<CPAN> module also provides a mechanism for locating packages or |
377
|
|
|
|
|
|
|
distributions, much like L<Package::Locator> does. However, L<CPAN> |
378
|
|
|
|
|
|
|
assumes that all repositories are CPAN mirrors, so it only searches |
379
|
|
|
|
|
|
|
the first repository that it can contact. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
My secret ambition is to fill the world with lots of DarkPAN |
382
|
|
|
|
|
|
|
repositories -- each with its own set of distributions. For that |
383
|
|
|
|
|
|
|
scenario, I need to search multiple repositories at the same time. |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head1 SEE ALSO |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
If you need to locate a distribution that contains a precise version |
388
|
|
|
|
|
|
|
of a file rather than just a version that is "new enough", then look |
389
|
|
|
|
|
|
|
at some of these: |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
L<Dist::Surveyor> |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
L<BackPAN::Index> |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
L<BackPAN::Version::Discover> |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head1 SUPPORT |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head2 Perldoc |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
perldoc Package::Locator |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=head2 Websites |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
The following websites have more information about this module, and may be of help to you. As always, |
408
|
|
|
|
|
|
|
in addition to those websites please use your favorite search engine to discover more resources. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=over 4 |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=item * |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
Search CPAN |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
The default CPAN search engine, useful to view POD in HTML format. |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
L<http://search.cpan.org/dist/Package-Locator> |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=item * |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
CPAN Ratings |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
The CPAN Ratings is a website that allows community ratings and reviews of Perl modules. |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
L<http://cpanratings.perl.org/d/Package-Locator> |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=item * |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
CPAN Testers |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
The CPAN Testers is a network of smokers who run automated tests on uploaded CPAN distributions. |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
L<http://www.cpantesters.org/distro/P/Package-Locator> |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=item * |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
CPAN Testers Matrix |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
The CPAN Testers Matrix is a website that provides a visual overview of the test results for a distribution on various Perls/platforms. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
L<http://matrix.cpantesters.org/?dist=Package-Locator> |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=item * |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
CPAN Testers Dependencies |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
The CPAN Testers Dependencies is a website that shows a chart of the test results of all dependencies for a distribution. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
L<http://deps.cpantesters.org/?module=Package::Locator> |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=back |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=head2 Bugs / Feature Requests |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
L<https://github.com/thaljef/Package-Locator/issues> |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=head2 Source Code |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
L<https://github.com/thaljef/Package-Locator> |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
git clone git://github.com/thaljef/Package-Locator.git |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head1 AUTHOR |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
Jeffrey Ryan Thalhammer <jeff@imaginative-software.com> |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
This software is copyright (c) 2011 by Imaginative Software Systems. |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
474
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=cut |