File Coverage

blib/lib/Acme/AutoLoad.pm
Criterion Covered Total %
statement 50 126 39.6
branch 16 80 20.0
condition 2 10 20.0
subroutine 8 11 72.7
pod 0 7 0.0
total 76 234 32.4


line stmt bran cond sub pod time code
1             package Acme::AutoLoad;
2              
3 1     1   172137 use strict;
  1         2  
  1         45  
4 1     1   5 use warnings;
  1         2  
  1         74  
5 1     1   6 use base qw(Exporter);
  1         4  
  1         5039  
6              
7             our $VERSION = '0.09';
8              
9             our $last_fetched = "";
10             our $lib = "lib";
11             our $hook = \&inc;
12              
13       0 0   sub ignore {}
14             sub import {
15 1 50   1   11 warn "DEBUG: Congratulations! Acme::AutoLoad has been loaded.\n" if $ENV{AUTOLOAD_DEBUG};
16 1 50       4 $lib = $ENV{AUTOLOAD_LIB} if $ENV{AUTOLOAD_LIB};
17 1 50       6 if ($lib =~ m{^[^/]}) {
18 1         2 eval {
19 1         7 require Cwd;
20 1         30 $lib = Cwd::abs_path($lib);
21             };
22             }
23 1 50       8 push @INC, $lib, $hook if $hook;
24 1         3 $hook = undef;
25 1         17 return \&ignore;
26             }
27              
28             sub mkbase {
29 4     4 0 27 my $path = shift;
30 4 50       54 if ($path =~ s{/+[^/]*$ }{}x) {
31 4 100       56 return 1 if -d $path;
32             }
33 2 50       21 die "$path: Not a directory\n" if lstat $path;
34 2 50       9 if (mkbase($path)) {
35 2 50       9 warn "DEBUG: mkbase: Creating [$path] ...\n" if $ENV{AUTOLOAD_DEBUG};
36 2         280 return mkdir $path, 0755;
37             }
38 0         0 return 0;
39             }
40              
41             sub fetch {
42 2     2 0 5 my $url = shift;
43 2   50     10 my $recurse = shift || {};
44 2 50       19 $url = full($url) unless $url =~ m{^\w+://};
45 2         8 my $contents = get($url);
46 0         0 $last_fetched = $url;
47 0 0       0 if ($contents =~ m{The document has moved }) {
48 0         0 my $bounce = $1;
49 0 0       0 return $contents if ++$recurse->{$bounce} > 3;
50 0 0       0 return fetch($bounce, $recurse) if ++$recurse->{total} < 21;
51             }
52 0         0 return $contents;
53             }
54              
55             # full
56             # Turn a relative URL into a full URL
57             sub full {
58 0     0 0 0 my $rel = shift;
59 0 0 0     0 if ($rel =~ m{http://} || $last_fetched !~ m{^(http://[^/]+)(/?.*)}) {
60 0         0 return $rel;
61             }
62 0         0 my $h = $1;
63 0         0 my $p = $2;
64 0 0       0 if ($rel =~ m{^/}) {
65 0         0 return "$h$rel";
66             }
67 0         0 $p =~ s{[^/]*$ }{}x;
68 0         0 return "$h$p$rel";
69             }
70              
71             # fly
72             # Create a stub module to load the real file on-the-fly if needed.
73             sub fly {
74 0     0 0 0 my $inc = shift;
75 0         0 my $url = shift;
76 0         0 my $write = shift;
77 0 0       0 warn "DEBUG: Creating stub for [$inc] in order to download [$url] later if needed.\n" if $ENV{AUTOLOAD_DEBUG};
78 0         0 my $contents = q{
79             my $url = q{$URL};
80             my $myself = $INC{"$inc"} || __FILE__;
81             warn "DEBUG: Downloading [$url] right now ...\n" if $ENV{AUTOLOAD_DEBUG};
82             my $m = Acme::AutoLoad::fetch($url);
83             if ($m =~ /package/) {
84             warn "DEBUG: Contents appear fine. Commencing BRICK OVER ...\n" if $ENV{AUTOLOAD_DEBUG};
85             if (open my $fh, ">", $myself) {
86             print $fh $m;
87             close $fh;
88             }
89             else {
90             warn "$myself: WARNING: Unable to repair! $!\n";
91             }
92             warn "DEBUG: Forcing re-evaluation of fresh module contents ...\n" if $ENV{AUTOLOAD_DEBUG};
93             my $e = eval $m;
94             if ($e) {
95             $INC{"$inc"} = $url;
96             $e;
97             }
98             else {
99             die "$url: $@\n";
100             }
101             }
102             else {
103             die "$url: STANKY! $m\n";
104             }
105             };
106 0         0 $contents =~ s/\s+/ /g;
107 0         0 $contents =~ s/([\;\{]+)\s+/$1\n/g;
108 0         0 $contents =~ s/^\s+//;
109 0         0 $contents =~ s/\s*$/\n/;
110             # Fake interpolation
111 0         0 $contents =~ s/\$URL/$url/g;
112 0         0 $contents =~ s/\$inc/$inc/g;
113 0 0       0 if ($write) {
114 0         0 mkbase($write);
115 0         0 $contents =~ s/(\$myself)\s*=.*?;/$1 = "$write";/;
116 0 0       0 open my $fh, ">", $write or die "$write: open: OUCH! $!";
117 0         0 print $fh $contents;
118 0         0 close $fh;
119             }
120 0         0 return $contents;
121             }
122              
123             sub inc {
124 2     2 0 174968 my $i = shift;
125 2         4 my $f = shift;
126 2         6 my $cache_file = "$lib/$f";
127 2 50       23 if (-f $cache_file) {
128 0         0 warn "$cache_file: Broken module. Can't continue.\n";
129 0         0 return ();
130             }
131 2 50       7 mkbase($cache_file) or die "$cache_file: Unable to create! $!\n";
132 2 50       13 shift @INC if $INC[0] eq \&ignore;
133              
134 2 50       17 if ($f =~ m{^(([\w/]+)\.pm)}) {
135 2         9 my $dist = my $mod = $2;
136 2         6 $f = $1;
137 2         11 $dist =~ s{/+}{-}g;
138 2         27 $mod =~ s{/+}{::}g;
139              
140 2   50     15 my $mapper = $ENV{AUTOLOAD_SRC} || "http://fastapi.metacpan.org/v1/module";
141 2         9 my $search = fetch("$mapper/$mod/");
142 0 0       0 warn "DEBUG: Probed: $last_fetched\n" if $ENV{AUTOLOAD_DEBUG};
143 0 0       0 if ($search =~ m{download_url.*?(\w+/[\w\-\.]+)\.tar.gz}) {
144 0         0 my $src = full("/source/$1/");
145 0 0 0     0 if ($search =~ m{"distribution"\s*:\s*"(.*?)"} && $dist ne $1) {
146 0 0       0 warn "DEBUG: Found module [$mod] as part of [$1] instead of [$dist]\n" if $ENV{AUTOLOAD_DEBUG};
147 0         0 $dist = $1;
148             }
149 0 0       0 if (my $MANIFEST = fetch "$src/MANIFEST") {
150 0 0       0 $src = $1 if $last_fetched =~ m{^(.*?)/+MANIFEST};
151 0 0       0 if ($MANIFEST =~ m{^lib/}m) {
152 0 0       0 warn "DEBUG: YEY! Found a lib/ somewhere!\n" if $ENV{AUTOLOAD_DEBUG};
153 0         0 while ($MANIFEST =~ s{^lib/(\S+\.pm)}{ }m) {
154 0         0 my $remote = $1;
155 0 0       0 warn "DEBUG: MATCH [lib/$remote] RIPPED OUT\n" if $ENV{AUTOLOAD_DEBUG};
156 0         0 $last_fetched = "$src/MANIFEST";
157 0         0 my $cache = "$lib/$remote";
158 0 0       0 if (!-f $cache) {
159 0         0 my $full = full("lib/$remote");
160 0         0 fly($remote,$full,$cache);
161             }
162             }
163             }
164             else {
165 0 0       0 warn "DEBUG: Oh, too bad there is no magic lib folder in the MANIFEST [$MANIFEST]\n" if $ENV{AUTOLOAD_DEBUG};
166             }
167 0 0       0 if (!-f $cache_file) {
168             # Old versions of h2xs used to toss the end module right into the base folder?
169 0 0       0 if ($f =~ m{(\w+\.pm)}) {
170 0         0 my $stub = $1;
171 0 0       0 if ($MANIFEST =~ /^(.*$stub)$/m) {
172 0         0 my $stab = $1;
173 0         0 $last_fetched = "$src/MANIFEST";
174 0         0 $stab = full($stab);
175 0         0 fly($f, $stab, $cache_file);
176             }
177             else {
178 0 0       0 warn "WARNING: No [$stub] in $src/MANIFEST? [$MANIFEST]" if $ENV{AUTOLOAD_DEBUG};
179 0         0 die "No [$stub] in $src/MANIFEST";
180             }
181             }
182             else {
183 0         0 warn "WARNING: Unable to extract stub from file [$f] ??\n";
184             }
185             }
186             }
187             else {
188 0         0 warn "$src: Incomplete distribution! Broken MANIFEST file?\n";
189             }
190             }
191             }
192              
193 0 0       0 if (open my $fh, "<", $cache_file) {
194 0         0 $INC{$f} = $cache_file;
195 0         0 return $fh;
196             }
197              
198 0         0 return ();
199             }
200              
201             sub get {
202 2     2 0 4 local $_ = shift;
203 2         14 s{^http(s|)://}{}i;
204 2         11 s{^([\w\-\.\:]+)$}{$1/};
205 2         18 s{^([\w\-\.]+)/}{$1:80/};
206 2 50       13 if (m{^([\w\-\.]+:\d+)(/.*)}) {
207 2         5 my $host = $1;
208 2         5 my $path = $2;
209 2 0       91 my $r = new IO::Socket::INET $host or return warn "$host$!\n";
210 0           $host =~ s/:\d+$//;
211 0           print $r "GET $path HTTP/1.0\r\nUser-Agent: Acme::AutoLoad/url::get\r\nHost: $host\r\n\r\n";
212 0           local $/;
213 0           return [split/[\r\n]{3,}/,<$r>,2]->[1];
214             }
215 0           return "";
216             }
217              
218             $INC{"Acme/AutoLoad.pm"} ||= __FILE__;
219              
220             warn "DEBUG: Congratulations! Acme::AutoLoad was compiled fine.\n" if $ENV{AUTOLOAD_DEBUG};
221              
222             1;
223             __END__