File Coverage

blib/lib/CPAN/Indexer/Mirror.pm
Criterion Covered Total %
statement 71 71 100.0
branch 10 18 55.5
condition 2 4 50.0
subroutine 26 26 100.0
pod 0 11 0.0
total 109 130 83.8


line stmt bran cond sub pod time code
1             package CPAN::Indexer::Mirror;
2              
3             =pod
4              
5             =head1 NAME
6              
7             CPAN::Indexer::Mirror - Creates the mirror.yml and mirror.json files
8              
9             =head1 SYNOPSIS
10              
11             use CPAN::Indexer::Mirror ();
12            
13             CPAN::Indexer::Mirror->new(
14             root => '/cpan/root/directory',
15             )->run;
16              
17             =head1 DESCRIPTION
18              
19             This module is used to implement a small piece of functionality inside the
20             CPAN/PAUSE indexer which generates F and F.
21              
22             These files are used to allow CPAN clients (via the L or
23             L modules) to implement mirror validation and automated
24             selection.
25              
26             =head1 METHODS
27              
28             Anyone who needs to know more detail than the SYNOPSIS should read the
29             (fairly straight forward) code.
30              
31             =cut
32              
33 2     2   67309 use 5.006;
  2         9  
  2         122  
34 2     2   14 use strict;
  2         3  
  2         82  
35 2     2   11 use File::Spec ();
  2         18  
  2         30  
36 2     2   1012 use File::Remove ();
  2         5057  
  2         47  
37 2     2   2516 use YAML::Tiny ();
  2         33075  
  2         65  
38 2     2   1928 use JSON ();
  2         44025  
  2         43  
39 2     2   5127 use URI ();
  2         39960  
  2         79  
40 2     2   6442 use URI::http ();
  2         31591  
  2         54  
41 2     2   8960 use IO::AtomicFile ();
  2         91949  
  2         58  
42 2     2   2366 use Parse::CPAN::MirroredBy ();
  2         35059  
  2         69  
43              
44 2     2   29 use vars qw{$VERSION};
  2         5  
  2         100  
45             BEGIN {
46 2     2   1555 $VERSION = '0.05';
47             }
48              
49              
50              
51              
52              
53             #####################################################################
54             # Constructor and Accessor Methods
55              
56             sub new {
57 1     1 0 1118 my $class = shift;
58 1         6 my $self = bless { @_ }, $class;
59              
60             # Apply defaults
61 1   50     14 $self->{name} ||= 'Comprehensive Perl Archive Network';
62 1   50     8 $self->{master} ||= 'http://www.cpan.org/';
63              
64 1         3 return $self;
65             }
66              
67             sub root {
68 3     3 0 63 $_[0]->{root};
69             }
70              
71             sub name {
72 1     1 0 7 $_[0]->{name};
73             }
74              
75             sub master {
76 1     1 0 6 $_[0]->{master};
77             }
78              
79             sub timestamp {
80 1 50   1 0 10 $_[0]->{timestamp} || $_[0]->now;
81             }
82              
83             sub mirrored_by {
84 1     1 0 5 File::Spec->catfile( $_[0]->root, 'MIRRORED.BY' );
85             }
86              
87             sub mirror_yml {
88 1     1 0 6 File::Spec->catfile( $_[0]->root, 'mirror.yml' );
89             }
90              
91             sub mirror_json {
92 1     1 0 4 File::Spec->catfile( $_[0]->root, 'mirror.json' );
93             }
94              
95              
96              
97              
98              
99             #####################################################################
100             # Process Methods
101              
102             sub run {
103 1 50   1 0 347 my $self = ref $_[0] ? shift : shift->new(@_);
104              
105             # Always randomise the mirror order, to protect against
106             # weak programmers on the other end scanning them in
107             # sequential order.
108 1         7 my @mirrors = sort { rand() <=> rand() }
  824         1555  
109             $self->parser->parse_file( $self->mirrored_by );
110              
111             # Generate the data structure for the files
112 1         36 my $data = {
113             version => '1.0',
114             name => $self->name,
115             master => $self->master,
116             timestamp => $self->timestamp,
117             mirrors => \@mirrors,
118             };
119              
120             # Write the mirror.yml and mirror.json file.
121             # Make sure the closes (and thus commits) are as close together
122             # as we can possibly get them, minimising race conditions.
123 1         5 SCOPE: {
124 1         22 local $!;
125 1         6 my $yaml_file = $self->mirror_yml;
126 1         6 my $json_file = $self->mirror_json;
127 1 50       13 my $yaml_fh = IO::AtomicFile->open($yaml_file, "w") or die "open: $!";
128 1 50       350 my $json_fh = IO::AtomicFile->open($json_file, "w") or die "open: $!";
129 1 50       207 $yaml_fh->print( YAML::Tiny::Dump($data) ) or die "print: $!";
130 1 50       9092 $json_fh->print( JSON->new->pretty->encode($data) ) or die "print: $!";
131 1 50       64 $yaml_fh->close or die "close: $!";
132 1 50       349 $json_fh->close or die "close: $!";
133             }
134              
135 1         231 return 1;
136             }
137              
138             sub parser {
139 1     1 0 13 my $parser = Parse::CPAN::MirroredBy->new;
140 1     242   17 $parser->add_map( sub { $_[0]->{dst_http} } );
  242         93410  
141             $parser->add_grep( sub {
142 242 100   242   4700 defined $_[0]
143             and
144             $_[0] =~ /\/$/
145 1         24 } );
146 1     154   15 $parser->add_map( sub { URI->new( $_[0], 'http' )->canonical->as_string } );
  154         1835  
147 1         11 return $parser;
148             }
149              
150             sub now {
151 1     1 0 31 my @t = gmtime time;
152 1         19 return sprintf( "%04u-%02u-%02uT%02u:%02u:%02uZ",
153             $t[5] + 1900,
154             $t[4] + 1,
155             $t[3],
156             $t[2],
157             $t[1],
158             $t[0],
159             );
160             }
161              
162             1;
163              
164             =pod
165              
166             =head1 SUPPORT
167              
168             Bugs should be reported via the CPAN bug tracker at
169              
170             L
171              
172             =head1 AUTHOR
173              
174             Adam Kennedy Eadamk@cpan.orgE
175              
176             =head1 SEE ALSO
177              
178             L, L,
179             L, L,
180             L
181              
182             =head1 COPYRIGHT
183              
184             Copyright 2008 Adam Kennedy.
185              
186             This program is free software; you can redistribute
187             it and/or modify it under the same terms as Perl itself.
188              
189             The full text of the license can be found in the
190             LICENSE file included with this module.
191              
192             =cut