File Coverage

blib/lib/Acme/AutoLoad.pm
Criterion Covered Total %
statement 18 126 14.2
branch 4 76 5.2
condition 0 10 0.0
subroutine 4 11 36.3
pod 0 7 0.0
total 26 230 11.3


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