File Coverage

blib/lib/CloudPAN.pm
Criterion Covered Total %
statement 65 70 92.8
branch 18 28 64.2
condition 11 26 42.3
subroutine 10 10 100.0
pod 0 1 0.0
total 104 135 77.0


line stmt bran cond sub pod time code
1             package CloudPAN;
2             {
3             $CloudPAN::VERSION = '1.131740';
4             }
5              
6             #ABSTRACT: Never install pure Perl modules again
7              
8 3     3   79499 use warnings;
  3         6  
  3         114  
9 3     3   14 use strict;
  3         3  
  3         104  
10 3     3   24 use File::Spec;
  3         6  
  3         63  
11 3     3   4570 use MetaCPAN::API::Tiny;
  3         251526  
  3         97  
12 3     3   35 use Symbol;
  3         8  
  3         254  
13 3     3   4983 use File::Temp;
  3         25667  
  3         241  
14 3     3   21 use File::Path;
  3         8  
  3         2551  
15              
16             our $options = {};
17              
18             sub import
19             {
20 3     3   856 my ($pkg, $opt) = @_;
21 3 100       53 return unless $opt;
22 1 50       6 die 'Options hash passed to CloudPAN for configuration needs to be a HashRef'
23             unless ref($opt) eq 'HASH';
24              
25 1 50       4 if(exists($opt->{persistence_location}))
26             {
27 1         2 my $loc = $opt->{persistence_location};
28              
29 1         72 File::Path::make_path($loc, {error => \my $err});
30              
31 1 50       6 if(@$err)
32             {
33 0         0 die '"persistence_location" must be a directory, readable, and writable by your effective uid/gid';
34             }
35            
36 1         50 $options->{location} = $loc;
37             }
38             else
39             {
40 0         0 die 'Options hash must have "persistence_location" defined';
41             }
42             }
43              
44             sub fetch_from_metacpan
45             {
46 6     6 0 16 my ($name) = @_;
47            
48 6         60 my $api = MetaCPAN::API::Tiny->new();
49              
50 6         669 my $content;
51              
52             eval
53             {
54 6         40 my $ret = $api->fetch('module/_search', q => qq|path:lib/$name AND status:latest|, size => 1, fields => 'author,release,path');
55            
56 6         203 die 'NoFetch'
57             unless $ret &&
58             exists($ret->{hits}) &&
59             exists($ret->{hits}->{hits}) &&
60             ref($ret->{hits}->{hits}) eq 'ARRAY' &&
61 6 50 33     201312 scalar(@{$ret->{hits}->{hits}}) &&
      33        
      33        
      50        
      66        
      66        
      33        
      33        
62             exists($ret->{hits}->{hits}->[0]->{fields}) &&
63             exists($ret->{hits}->{hits}->[0]->{fields}->{author}) &&
64             exists($ret->{hits}->{hits}->[0]->{fields}->{release}) &&
65             exists($ret->{hits}->{hits}->[0]->{fields}->{path});
66              
67 4         18 my $fields = $ret->{hits}->{hits}->[0]->{fields};
68              
69 4         19 my $req_url = join('/', $api->{base_url}, 'source', @{$fields}{qw/author release path/});
  4         27  
70            
71 4         220 my $response = $api->{ua}->get($req_url);
72            
73 4 50 33     81868 die 'HTTP'
74             unless $response->{success} &&
75             length $response->{content};
76            
77 4         337 $content = $response->{content};
78             }
79             or do
80 6 100       14 {
81 2 50       254 if("$@" eq 'NoFetch')
    50          
82             {
83 0         0 die "MetaCPAN does not seem to know about your module: $name";
84             }
85             elsif("$@" eq 'HTTP')
86             {
87 0         0 die "There was a problem attempting to fetch the module contents from MetaCPAN for module: $name";
88             }
89             };
90              
91 6         1366 return \$content;
92             }
93              
94             BEGIN {
95              
96             push(@INC, sub {
97 7         10361 my ($self, $name) = @_;
98              
99 7 100       40 if (exists($options->{location}))
100             {
101 4         245 my $path = File::Spec->rel2abs($name, $options->{location});
102 4 100       228 if (-e $path)
103             {
104 1 50       56 open(my $fh, '<', $path)
105             or die "Unable to open cached copy of module located at $path";
106              
107 1         71 return $fh;
108             }
109             else
110             {
111 3         59 my ($volume, $dir, $file) = File::Spec->splitpath($path);
112 3         29 my $to_create_dir = File::Spec->catpath($volume, $dir, '');
113            
114 3         618 File::Path::make_path($to_create_dir, {error => \my $err});
115              
116 3 50       17 if(@$err)
117             {
118 0         0 die "Failed to create necessary path within persistence_location: $to_create_dir";
119             }
120              
121 3         11 my $content_ref = fetch_from_metacpan($name);
122 3 50       747 open(my $fh, '+>', $path)
123             or die "Unable to write cached copy of module located at $path";
124              
125 3         590 print $fh $$content_ref;
126 3         208 seek($fh, 0, 0);
127 3         1218 return $fh;
128             }
129             }
130             else
131             {
132 3         13 my $content_ref = fetch_from_metacpan($name);
133 3         27 my $fh = File::Temp::tempfile(UNLINK => 1);
134 3         4070 print $fh $$content_ref;
135 3         115 seek($fh, 0, 0);
136 3         970 return $fh;
137             }
138 3     3   98 });
139             }
140              
141             1;
142              
143             __END__