line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mirror::URI; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Abstract base module to allow easy extension to other file formats. |
4
|
|
|
|
|
|
|
|
5
|
4
|
|
|
4
|
|
1637
|
use 5.00503; |
|
4
|
|
|
|
|
16
|
|
|
4
|
|
|
|
|
157
|
|
6
|
4
|
|
|
4
|
|
22
|
use strict; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
121
|
|
7
|
4
|
|
|
4
|
|
31
|
use Carp (); |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
71
|
|
8
|
4
|
|
|
4
|
|
18
|
use File::Spec (); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
60
|
|
9
|
4
|
|
|
4
|
|
4290
|
use Time::HiRes (); |
|
4
|
|
|
|
|
8725
|
|
|
4
|
|
|
|
|
135
|
|
10
|
4
|
|
|
4
|
|
3136
|
use Time::Local (); |
|
4
|
|
|
|
|
6444
|
|
|
4
|
|
|
|
|
84
|
|
11
|
4
|
|
|
4
|
|
3109
|
use URI (); |
|
4
|
|
|
|
|
23400
|
|
|
4
|
|
|
|
|
156
|
|
12
|
4
|
|
|
4
|
|
4853
|
use URI::file (); |
|
4
|
|
|
|
|
24915
|
|
|
4
|
|
|
|
|
94
|
|
13
|
4
|
|
|
4
|
|
3448
|
use URI::http (); |
|
4
|
|
|
|
|
9418
|
|
|
4
|
|
|
|
|
98
|
|
14
|
4
|
|
|
4
|
|
28454
|
use Params::Util qw{ _STRING _POSINT _ARRAY0 _INSTANCE }; |
|
4
|
|
|
|
|
16081
|
|
|
4
|
|
|
|
|
524
|
|
15
|
4
|
|
|
4
|
|
2797
|
use LWP::Simple (); |
|
4
|
|
|
|
|
290631
|
|
|
4
|
|
|
|
|
113
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# Time values have an extra 5 minute fudge factor |
18
|
4
|
|
|
4
|
|
33
|
use constant ONE_DAY => 86700; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
263
|
|
19
|
4
|
|
|
4
|
|
26
|
use constant TWO_DAYS => 172800; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
177
|
|
20
|
4
|
|
|
4
|
|
20
|
use constant THIRTY_DAYS => 2592000; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
162
|
|
21
|
|
|
|
|
|
|
|
22
|
4
|
|
|
4
|
|
26
|
use vars qw{$VERSION}; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
256
|
|
23
|
|
|
|
|
|
|
BEGIN { |
24
|
4
|
|
|
4
|
|
6229
|
$VERSION = '0.04_01'; |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
##################################################################### |
32
|
|
|
|
|
|
|
# Constructor and Accessors |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub new { |
35
|
5
|
|
|
5
|
0
|
13
|
my $class = shift; |
36
|
5
|
|
|
|
|
43
|
my $self = bless { @_ }, $class; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Clean up params |
39
|
5
|
|
|
|
|
29
|
$self->{class} = $class; |
40
|
5
|
|
|
|
|
35
|
$self->{valid} = !! $self->valid; |
41
|
5
|
100
|
|
|
|
16
|
if ( $self->valid ) { |
42
|
2
|
50
|
|
|
|
17
|
if ( _STRING($self->master) ) { |
43
|
2
|
|
|
|
|
7
|
$self->{master} = URI->new( $self->master ); |
44
|
|
|
|
|
|
|
} |
45
|
2
|
50
|
|
|
|
364
|
unless ( _INSTANCE($self->master, 'URI') ) { |
46
|
0
|
|
|
|
|
0
|
Carp::croak("Missing or invalid 'master' value"); |
47
|
|
|
|
|
|
|
} |
48
|
2
|
50
|
33
|
|
|
104
|
if ( _STRING($self->{timestamp}) and ! _POSINT($self->{timestamp}) ) { |
49
|
2
|
50
|
|
|
|
43
|
unless ( $self->{timestamp} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/ ) { |
50
|
0
|
|
|
|
|
0
|
Carp::croak("Invalid timestamp format"); |
51
|
|
|
|
|
|
|
} |
52
|
2
|
|
|
|
|
23
|
$self->{timestamp} = Time::Local::timegm( $6, $5, $4, $3, $2 - 1, $1 ); |
53
|
|
|
|
|
|
|
} |
54
|
2
|
|
|
|
|
100
|
my $mirrors = $self->{mirrors}; |
55
|
2
|
50
|
|
|
|
11
|
unless ( _ARRAY0($mirrors) ) { |
56
|
0
|
|
|
|
|
0
|
croak("Invalid mirror list"); |
57
|
|
|
|
|
|
|
} |
58
|
2
|
|
|
|
|
11
|
foreach my $i ( 0 .. $#$mirrors ) { |
59
|
15
|
50
|
|
|
|
746
|
next unless _STRING($mirrors->[$i]); |
60
|
15
|
|
|
|
|
43
|
$mirrors->[$i] = URI->new( $mirrors->[$i] ); |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
5
|
|
|
|
|
160
|
return $self; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub class { |
68
|
2
|
|
|
2
|
0
|
16
|
$_[0]->{class}; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub version { |
72
|
3
|
|
|
3
|
0
|
756
|
$_[0]->{version}; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub uri { |
76
|
2
|
|
|
2
|
0
|
14
|
$_[0]->{uri}; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub name { |
80
|
4
|
|
|
4
|
0
|
518
|
$_[0]->{name}; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub master { |
84
|
12
|
|
|
12
|
0
|
409
|
$_[0]->{master}; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub timestamp { |
88
|
2
|
|
|
2
|
0
|
10
|
$_[0]->{timestamp}; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub mirrors { |
92
|
1
|
|
|
1
|
0
|
3
|
return ( @{ $_[0]->{mirrors} } ); |
|
1
|
|
|
|
|
7
|
|
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub valid { |
96
|
13
|
|
|
13
|
0
|
6451
|
$_[0]->{valid}; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub lastget { |
100
|
2
|
|
|
2
|
0
|
15
|
$_[0]->{lastget}; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub lag { |
104
|
2
|
|
|
2
|
0
|
14
|
$_[0]->{lag}; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub age { |
108
|
2
|
|
|
2
|
0
|
26
|
$_[0]->{lastget} - $_[0]->{timestamp}; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
##################################################################### |
116
|
|
|
|
|
|
|
# Load Methods |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub read { |
119
|
3
|
|
|
3
|
0
|
4247
|
my $class = shift; |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# Check the file to read |
122
|
3
|
|
|
|
|
7
|
my $root = shift; |
123
|
3
|
50
|
33
|
|
|
100
|
unless ( defined _STRING($root) and -d $root ) { |
124
|
0
|
|
|
|
|
0
|
Carp::croak("Directory '$root' does not exist"); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Convert to a usable URI |
128
|
3
|
|
|
|
|
333
|
my $uri = URI::file->new( |
129
|
|
|
|
|
|
|
File::Spec->canonpath( |
130
|
|
|
|
|
|
|
File::Spec->rel2abs($root) |
131
|
|
|
|
|
|
|
) |
132
|
|
|
|
|
|
|
)->canonical; |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# In a URI a directory must have an explicit trailing slash |
135
|
3
|
|
|
|
|
13808
|
$uri->path( $uri->path . '/' ); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Hand off to the URI fetcher |
138
|
3
|
|
|
|
|
259
|
return $class->get( $uri, @_ ); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub get { |
142
|
5
|
|
|
5
|
0
|
14
|
my $class = shift; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# Check the URI |
145
|
5
|
|
|
|
|
12
|
my $base = shift; |
146
|
5
|
50
|
|
|
|
67
|
unless ( _INSTANCE($base, 'URI') ) { |
147
|
0
|
|
|
|
|
0
|
Carp::croak("Missing or invalid URI"); |
148
|
|
|
|
|
|
|
} |
149
|
5
|
50
|
|
|
|
91
|
unless ( $base->path =~ /\/$/ ) { |
150
|
0
|
|
|
|
|
0
|
Carp::croak("URI must have a trailing slash"); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Find the file within the root path |
154
|
5
|
|
|
|
|
213
|
my %self = ( |
155
|
|
|
|
|
|
|
uri => URI->new( $class->filename )->abs($base)->canonical, |
156
|
|
|
|
|
|
|
); |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# Pull the file and time it |
159
|
5
|
|
|
|
|
2467
|
$self{lastget} = Time::HiRes::time; |
160
|
5
|
|
|
|
|
39
|
$self{string} = LWP::Simple::get($self{uri}); |
161
|
5
|
|
|
|
|
125046
|
$self{lag} = Time::HiRes::time - $self{lastget}; |
162
|
5
|
100
|
|
|
|
32
|
unless ( defined $self{string} ) { |
163
|
3
|
|
|
|
|
40
|
return $class->new( %self, valid => 0 ); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# Parse the file |
167
|
2
|
|
|
|
|
26
|
my $hash = $class->parse( $self{string} ); |
168
|
2
|
50
|
|
|
|
15
|
unless ( ref $hash eq 'HASH' ) { |
169
|
0
|
|
|
|
|
0
|
return $class->new( %self, valid => 0 ); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# Create the object |
173
|
2
|
|
|
|
|
45
|
return $class->new( %$hash, %self, valid => 1 ); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
##################################################################### |
181
|
|
|
|
|
|
|
# Populate Elements |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub get_master { |
184
|
1
|
|
|
1
|
0
|
4
|
my $self = shift; |
185
|
1
|
50
|
|
|
|
5
|
if ( _INSTANCE($self->master, 'URI') ) { |
186
|
|
|
|
|
|
|
# Load the master |
187
|
1
|
|
|
|
|
18
|
my $master = $self->class->get($self->master); |
188
|
1
|
|
|
|
|
5
|
$self->{master} = $master; |
189
|
|
|
|
|
|
|
} |
190
|
1
|
|
|
|
|
8
|
return $self->master; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub get_mirror { |
194
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
195
|
1
|
|
|
|
|
3
|
my $i = shift; |
196
|
1
|
|
|
|
|
5
|
my $uri = $self->{mirrors}->[$i]; |
197
|
1
|
50
|
|
|
|
7
|
unless ( defined $uri ) { |
198
|
0
|
|
|
|
|
0
|
Carp::croak("No mirror with index $i"); |
199
|
|
|
|
|
|
|
} |
200
|
1
|
50
|
|
|
|
152
|
if ( _INSTANCE($uri, 'URI') ) { |
201
|
1
|
|
|
|
|
13
|
my $mirror = $self->class->get($uri); |
202
|
1
|
|
|
|
|
6
|
$self->{mirrors}->[$i] = $mirror; |
203
|
|
|
|
|
|
|
} |
204
|
1
|
|
|
|
|
8
|
return $self->{mirrors}->[$i]; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
1; |