line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mirror::YAML; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
622373
|
use 5.00503; |
|
4
|
|
|
|
|
16
|
|
|
4
|
|
|
|
|
157
|
|
4
|
4
|
|
|
4
|
|
22
|
use strict; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
113
|
|
5
|
4
|
|
|
4
|
|
1613
|
use Mirror::URI (); |
|
4
|
|
|
|
|
18
|
|
|
4
|
|
|
|
|
87
|
|
6
|
4
|
|
|
4
|
|
5897
|
use Parse::CPAN::Meta (); |
|
4
|
|
|
|
|
6334
|
|
|
4
|
|
|
|
|
99
|
|
7
|
|
|
|
|
|
|
|
8
|
4
|
|
|
4
|
|
29
|
use vars qw{$VERSION @ISA}; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
345
|
|
9
|
|
|
|
|
|
|
BEGIN { |
10
|
4
|
|
|
4
|
|
10
|
$VERSION = '0.04_01'; |
11
|
4
|
|
|
|
|
1733
|
@ISA = 'Mirror::URI'; |
12
|
|
|
|
|
|
|
} |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
##################################################################### |
19
|
|
|
|
|
|
|
# Implementation-Specific Methods |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub filename { |
22
|
5
|
|
|
5
|
0
|
29
|
return 'mirror.yml'; |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub parse { |
26
|
2
|
|
|
2
|
0
|
5
|
my $class = shift; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Make sure we actually have a YAML document |
29
|
2
|
50
|
|
|
|
15
|
unless ( $_[0] =~ /^---/ ) { |
30
|
0
|
|
|
|
|
0
|
return undef; |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Parse the file |
34
|
2
|
|
|
|
|
15
|
my @docs = Parse::CPAN::Meta::Load( $_[0] ); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# We only care about the first document |
37
|
2
|
50
|
|
|
|
18818
|
if ( defined $docs[0] ) { |
38
|
2
|
|
|
|
|
14
|
return $docs[0]; |
39
|
|
|
|
|
|
|
} else { |
40
|
0
|
|
|
|
|
|
Carp::croak("Illegal YAML document"); |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
1; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=pod |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 NAME |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
Mirror::YAML - Mirror Configuration and Auto-Discovery |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 DESCRIPTION |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
A C file is used to allow a repository client to reliably and |
55
|
|
|
|
|
|
|
robustly locate, identify, validate and age a repository. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
It contains a timestamp for when the repository was last updated, the URI |
58
|
|
|
|
|
|
|
for the master repository, and a list of all the current mirrors at the |
59
|
|
|
|
|
|
|
time the repository was last updated. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
B contains all the functionality requires to both create |
62
|
|
|
|
|
|
|
and read the F files, and the logic to select one or more |
63
|
|
|
|
|
|
|
mirrors entirely automatically. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
It currently scales cleanly for a dozen or so mirrors, but may be slow |
66
|
|
|
|
|
|
|
when used with very large repositories with a hundred or more mirrors. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 Methodology |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
A variety of simple individual mechanisms are combined to provide a |
71
|
|
|
|
|
|
|
completely robust discovery and validation system. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
B |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
The F file should exist in a standard location, typically at |
76
|
|
|
|
|
|
|
the root of the repository. The file is very small (no more than a few |
77
|
|
|
|
|
|
|
kilobytes at most) so the overhead of fetching one (or several) of them |
78
|
|
|
|
|
|
|
is negligable. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
The file is pulled via FTP or HTTP. Once pulled, the first three |
81
|
|
|
|
|
|
|
characters are examined to validate it is a YAML file and not a |
82
|
|
|
|
|
|
|
login page for a "captured hotspot" such as at hotels and airports. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
The shorter ".yml" is used in the file name to allow for Mirror::YAML |
85
|
|
|
|
|
|
|
to be used even in the rare situation of mirrors that must work |
86
|
|
|
|
|
|
|
on operating systems with (now relatively rare) 8.3 filesystems. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
B |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Because the F file is small (in simple cases only one or two |
91
|
|
|
|
|
|
|
packets) the download time can be used to measure the responsiveness of |
92
|
|
|
|
|
|
|
that mirror. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
By pulling the files from several mirrors, the comparative download |
95
|
|
|
|
|
|
|
times can be used as part of the process of selecting the fastest mirror. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
B |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
The mirror.yml file contains a timestamp that records the last update time |
100
|
|
|
|
|
|
|
for the repository. This timestamp should be updated every repository |
101
|
|
|
|
|
|
|
update cycle, even if there are no actual changes to the repository. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Once a F file has been fetched correctly, the timestamp can |
104
|
|
|
|
|
|
|
then be used to verify the age of the mirror. Whereas a perfectly up to |
105
|
|
|
|
|
|
|
date mirror will show an age of less than an hour (assuming that the |
106
|
|
|
|
|
|
|
repository master updates every hour) a repository that has stopped |
107
|
|
|
|
|
|
|
updating will show an age that is greater than the longest mirror rate |
108
|
|
|
|
|
|
|
plus the update cycle time. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Thus, any mirror that as "gone stale" can be filter out of the potential |
111
|
|
|
|
|
|
|
mirrors to use. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
For portability, the timestamp is recording in ISO format Zulu time. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
B |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
The F file contains a link to the master repository. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
If the L client has an out-of-date current state at some |
120
|
|
|
|
|
|
|
point, it will use the master repository URI in the current state to |
121
|
|
|
|
|
|
|
pull a fresh F from the master repository. |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
This solves the most-simple case, but other cases require a little |
124
|
|
|
|
|
|
|
more complexity (which we'll address later). |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
B |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
The F file contains a simple list of all mirror URIs. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Apart from filtering the list to try and find the best mirror to use, |
131
|
|
|
|
|
|
|
the mirror list allows the B client to have backup |
132
|
|
|
|
|
|
|
options for locating the master repository if it moves, or the |
133
|
|
|
|
|
|
|
bootstrap F file has gotten old. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
If the client can't find the master repository (because it has moved) |
136
|
|
|
|
|
|
|
the client will scan the list of mirrors to try to find the location |
137
|
|
|
|
|
|
|
of the updated repository. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
B |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
To bootstrap the client, it should come with a default bootstrap |
142
|
|
|
|
|
|
|
F file built into it. When the client starts up for the |
143
|
|
|
|
|
|
|
first time, it will attempt to fetch an updated mirror.yml from the |
144
|
|
|
|
|
|
|
master repository, and if that doesn't exist will pull from the |
145
|
|
|
|
|
|
|
default list of mirrors until it can find more than one up to date |
146
|
|
|
|
|
|
|
mirror that agrees on the real location of the master server. |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
B |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
On top of the straight forward mirror discovery functionality, the |
151
|
|
|
|
|
|
|
client algorithm contains additional logic to deal with either a |
152
|
|
|
|
|
|
|
mirror or the master server goes bad. While likely not 100% secure |
153
|
|
|
|
|
|
|
it heads off several attack scenarios to prevent anyone trying them, |
154
|
|
|
|
|
|
|
and provides as much as can be expected without resorting to cryto |
155
|
|
|
|
|
|
|
and certificates. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head1 SUPPORT |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Bugs should be reported via the CPAN bug tracker at |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
L |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
For other issues, or commercial enhancement or support, contact the author. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head1 AUTHOR |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Adam Kennedy Eadamk@cpan.orgE |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head1 SEE ALSO |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
L |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=head1 COPYRIGHT |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Copyright 2007 - 2008 Adam Kennedy. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
This program is free software; you can redistribute |
178
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
The full text of the license can be found in the |
181
|
|
|
|
|
|
|
LICENSE file included with this module. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=cut |