line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package PAR::Repository::Client::Local; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
224
|
use 5.006; |
|
9
|
|
|
|
|
35
|
|
|
9
|
|
|
|
|
1048
|
|
4
|
9
|
|
|
9
|
|
49
|
use strict; |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
307
|
|
5
|
9
|
|
|
9
|
|
44
|
use warnings; |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
260
|
|
6
|
|
|
|
|
|
|
|
7
|
9
|
|
|
9
|
|
43
|
use base 'PAR::Repository::Client'; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
950
|
|
8
|
|
|
|
|
|
|
|
9
|
9
|
|
|
9
|
|
48
|
use Carp qw/croak/; |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
12103
|
|
10
|
|
|
|
|
|
|
require File::Copy; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.24'; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 NAME |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
PAR::Repository::Client::Local - PAR repo. on the local file system |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 SYNOPSIS |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
use PAR::Repository::Client; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my $client = PAR::Repository::Client->new( |
23
|
|
|
|
|
|
|
uri => 'file:///foo/repository', |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 DESCRIPTION |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
This module implements repository accesses on the local filesystem. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
If you create a new L object and pass it |
31
|
|
|
|
|
|
|
an uri parameter which starts with C or just a path, |
32
|
|
|
|
|
|
|
it will create an object of this class. It inherits from |
33
|
|
|
|
|
|
|
C. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head2 EXPORT |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
None. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 METHODS |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Following is a list of class and instance methods. |
42
|
|
|
|
|
|
|
(Instance methods until otherwise mentioned.) |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=cut |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head2 fetch_par |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Fetches a .par distribution from the repository and stores it |
49
|
|
|
|
|
|
|
locally. Returns the name of the local file or the empty list on |
50
|
|
|
|
|
|
|
failure. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
First argument must be the distribution name to fetch. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub fetch_par { |
57
|
4
|
|
|
4
|
1
|
8
|
my $self = shift; |
58
|
4
|
|
|
|
|
18
|
$self->{error} = undef; |
59
|
4
|
|
|
|
|
13
|
my $dist = shift; |
60
|
4
|
50
|
|
|
|
20
|
if (not defined $dist) { |
61
|
0
|
|
|
|
|
0
|
$self->{error} = "undef passed as argument to fetch_par()"; |
62
|
0
|
|
|
|
|
0
|
return(); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
4
|
|
|
|
|
15
|
my $path = $self->{uri}; |
66
|
4
|
|
|
|
|
26
|
$path =~ s/(?:\/|\\)$//; |
67
|
4
|
|
|
|
|
25
|
$path =~ s!^file://!!i; |
68
|
|
|
|
|
|
|
|
69
|
4
|
|
|
|
|
28
|
my ($dname, $vers, $arch, $perl) = PAR::Dist::parse_dist_name($dist); |
70
|
4
|
|
|
|
|
1348
|
my $file = File::Spec->catfile( |
71
|
|
|
|
|
|
|
File::Spec->catdir($path, $arch, $perl), |
72
|
|
|
|
|
|
|
"$dname-$vers-$arch-$perl.par" |
73
|
|
|
|
|
|
|
); |
74
|
|
|
|
|
|
|
|
75
|
4
|
50
|
|
|
|
251
|
if (not -f $file) { |
76
|
0
|
|
|
|
|
0
|
$self->{error} = "Could not find distribution in local repository at '$file'"; |
77
|
0
|
|
|
|
|
0
|
return(); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
4
|
|
|
|
|
21
|
return $file; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head2 validate_repository |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Makes sure the repository is valid. Returns the empty list |
86
|
|
|
|
|
|
|
if that is not so and a true value if the repository is valid. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
Checks that the repository version is compatible. |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
The error message is available as C<$client->error()> on |
91
|
|
|
|
|
|
|
failure. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=cut |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub validate_repository { |
96
|
9
|
|
|
9
|
1
|
24
|
my $self = shift; |
97
|
9
|
|
|
|
|
25
|
$self->{error} = undef; |
98
|
|
|
|
|
|
|
|
99
|
9
|
|
|
|
|
90
|
my $mod_db = $self->modules_dbm; |
100
|
|
|
|
|
|
|
|
101
|
9
|
50
|
|
|
|
47
|
return() unless defined $mod_db; |
102
|
|
|
|
|
|
|
|
103
|
9
|
100
|
|
|
|
140
|
return() unless $self->validate_repository_version; |
104
|
|
|
|
|
|
|
|
105
|
8
|
|
|
|
|
47
|
return 1; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head2 _repository_info |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Returns a YAML::Tiny object representing the repository meta |
111
|
|
|
|
|
|
|
information. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
This is a private method. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=cut |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub _repository_info { |
118
|
9
|
|
|
9
|
|
24
|
my $self = shift; |
119
|
9
|
|
|
|
|
23
|
$self->{error} = undef; |
120
|
9
|
50
|
|
|
|
48
|
return $self->{info} if defined $self->{info}; |
121
|
|
|
|
|
|
|
|
122
|
9
|
|
|
|
|
28
|
my $path = $self->{uri}; |
123
|
9
|
|
|
|
|
47
|
$path =~ s/(?:\/|\\)$//; |
124
|
9
|
|
|
|
|
52
|
$path =~ s!^file://!!i; |
125
|
|
|
|
|
|
|
|
126
|
9
|
|
|
|
|
216
|
my $file = File::Spec->catfile($path, PAR::Repository::Client::REPOSITORY_INFO_FILE()); |
127
|
|
|
|
|
|
|
|
128
|
9
|
50
|
33
|
|
|
320
|
if (not defined $file or not -f $file) { |
129
|
0
|
|
|
|
|
0
|
$self->{error} = "File '$file' does not exist in repository."; |
130
|
0
|
|
|
|
|
0
|
return(); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
9
|
|
|
|
|
104
|
my $yaml = YAML::Tiny->new->read($file); |
134
|
9
|
50
|
|
|
|
67233
|
if (not defined $yaml) { |
135
|
0
|
|
|
|
|
0
|
$self->{error} = "Error reading repository info from YAML file."; |
136
|
0
|
|
|
|
|
0
|
return(); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# workaround for possible YAML::Syck/YAML::Tiny bug |
140
|
|
|
|
|
|
|
# This is not the right way to do it! |
141
|
9
|
50
|
|
|
|
53
|
@$yaml = ($yaml->[1]) if @$yaml > 1; |
142
|
9
|
|
|
|
|
33
|
$self->{info} = $yaml; |
143
|
9
|
|
|
|
|
54
|
return $yaml; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head2 _fetch_dbm_file |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
This is a private method. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
Fetches a dbm (index) file from the repository and |
151
|
|
|
|
|
|
|
returns the name of the local file or the |
152
|
|
|
|
|
|
|
empty list on failure. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
An error message is available via the C |
155
|
|
|
|
|
|
|
method in case of failure. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=cut |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub _fetch_dbm_file { |
160
|
13
|
|
|
13
|
|
25
|
my $self = shift; |
161
|
13
|
|
|
|
|
29
|
$self->{error} = undef; |
162
|
13
|
|
|
|
|
25
|
my $file = shift; |
163
|
13
|
50
|
|
|
|
39
|
return if not defined $file; |
164
|
|
|
|
|
|
|
|
165
|
13
|
|
|
|
|
34
|
my $path = $self->{uri}; |
166
|
13
|
|
|
|
|
50
|
$path =~ s/(?:\/|\\)$//; |
167
|
13
|
|
|
|
|
63
|
$path =~ s!^file://!!i; |
168
|
|
|
|
|
|
|
|
169
|
13
|
|
|
|
|
172
|
my $url = File::Spec->catfile( $path, $file ); |
170
|
|
|
|
|
|
|
|
171
|
13
|
50
|
|
|
|
254
|
if (not -f $url) { |
172
|
0
|
|
|
|
|
0
|
$self->{error} = "Could not find dbm file in local repository at '$url'"; |
173
|
0
|
|
|
|
|
0
|
return(); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
13
|
|
|
|
|
102
|
my ($tempfh, $tempfile) = File::Temp::tempfile( |
177
|
|
|
|
|
|
|
'temp_zip_dbm_XXXXX', |
178
|
|
|
|
|
|
|
UNLINK => 1, # because we cache the suckers by default |
179
|
|
|
|
|
|
|
DIR => $self->{cache_dir}, |
180
|
|
|
|
|
|
|
EXLOCK => 0, # FIXME no exclusive locking or else we block on BSD. What's the right solution? |
181
|
|
|
|
|
|
|
); |
182
|
|
|
|
|
|
|
|
183
|
13
|
|
|
|
|
307108
|
File::Copy::copy($url, $tempfile); |
184
|
|
|
|
|
|
|
|
185
|
13
|
|
|
|
|
65915
|
return $tempfile; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=head2 _dbm_checksums |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
This is a private method. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
If the repository has a checksums file (new feature of |
195
|
|
|
|
|
|
|
C 0.15), this method returns a hash |
196
|
|
|
|
|
|
|
associating the DBM file names (e.g. C) |
197
|
|
|
|
|
|
|
with their MD5 hashes (base 64). |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
This method B queries the repository and never caches |
200
|
|
|
|
|
|
|
the information locally. That's the whole point of having the |
201
|
|
|
|
|
|
|
checksums. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
In case the repository does not have checksums, this method |
204
|
|
|
|
|
|
|
returns the empty list, so check the return value! |
205
|
|
|
|
|
|
|
The error message (see the C method) will be |
206
|
|
|
|
|
|
|
I<"Repository does not support checksums"> in that case. |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=cut |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub _dbm_checksums { |
211
|
45
|
|
|
45
|
|
78
|
my $self = shift; |
212
|
45
|
|
|
|
|
90
|
$self->{error} = undef; |
213
|
|
|
|
|
|
|
|
214
|
45
|
|
|
|
|
105
|
my $path = $self->{uri}; |
215
|
45
|
|
|
|
|
162
|
$path =~ s/(?:\/|\\)$//; |
216
|
45
|
|
|
|
|
216
|
$path =~ s!^file://!!i; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# if we're running on a "trust-the-checksums-for-this-long" basis... |
219
|
|
|
|
|
|
|
# ... return if the timeout hasn't elapsed |
220
|
45
|
50
|
66
|
|
|
343
|
if ($self->{checksums} and $self->{checksums_timeout}) { |
221
|
0
|
|
|
|
|
0
|
my $time = time(); |
222
|
0
|
0
|
|
|
|
0
|
if ($time - $self->{last_checksums_refresh} < $self->{checksums_timeout}) { |
223
|
0
|
|
|
|
|
0
|
return($self->{checksums}); |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
45
|
|
|
|
|
778
|
my $file = File::Spec->catfile($path, PAR::Repository::Client::DBM_CHECKSUMS_FILE()); |
228
|
|
|
|
|
|
|
|
229
|
45
|
50
|
33
|
|
|
2631
|
if (not defined $file or not -f $file) { |
230
|
0
|
|
|
|
|
0
|
$self->{error} = "Repository does not support checksums"; |
231
|
0
|
|
|
|
|
0
|
return(); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
45
|
|
|
|
|
274
|
return $self->_parse_dbm_checksums($file); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=head2 _init |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
This private method is called by the C method of |
241
|
|
|
|
|
|
|
L. It is used to initialize |
242
|
|
|
|
|
|
|
the client object and C passes it a hash ref to |
243
|
|
|
|
|
|
|
its arguments. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
Should return a true value on success. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=cut |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub _init { |
250
|
|
|
|
|
|
|
# We implement additional object attributes here |
251
|
|
|
|
|
|
|
# Currently no extra attributes... |
252
|
9
|
|
|
9
|
|
26
|
return 1; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
1; |
257
|
|
|
|
|
|
|
__END__ |