File Coverage

blib/lib/App/NoPAN.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             package App::NoPAN;
2              
3 2     2   11 use strict;
  2         48  
  2         76  
4 2     2   11 use warnings;
  2         5  
  2         81  
5              
6 2     2   12 use base qw(Class::Accessor::Fast);
  2         4  
  2         1904  
7             use Cwd;
8             use File::Temp qw(tempdir);
9             use HTML::LinkExtor;
10             use List::Util qw(first);
11             use LWP::Simple ();
12             use Scope::Guard;
13             use URI::Escape qw/uri_unescape/;
14              
15             # FIXME find and automatically load NoPAN::Installer::*.pm
16             require App::NoPAN::Installer::Perl;
17             require App::NoPAN::Installer::Configure;
18             require App::NoPAN::Installer::Makefile; # should better be the last
19              
20             our %Defaults = (
21             opt_install => 1,
22             opt_test => undef, # tristate: 0:no, 1:yes, undef:default
23             );
24             my @Installers;
25              
26             __PACKAGE__->mk_accessors(keys %Defaults);
27              
28             sub new {
29             my ($klass, %opts) = @_;
30             bless {
31             %Defaults,
32             %opts,
33             }, $klass;
34             }
35              
36             sub run {
37             my ($self, $url) = @_;
38            
39             die "invalid URL:$url"
40             unless $url =~ m{^[a-z]+://};
41            
42             $url .= '/'
43             unless $url =~ m|/$|;
44             warn "downloading files from URL:$url\n";
45             my @root_files = $self->files_from_dir($url);
46            
47             my $installer_class =
48             first { $_->can_install($self, \@root_files) } @Installers;
49             die "do not know how to install:$url" unless $installer_class;
50            
51             my $workdir = tempdir(CLEANUP => 1);
52             $self->fetch_all($url, $workdir, '', \@root_files);
53            
54             {
55             my $pwd = getcwd;
56             my $popdir = Scope::Guard->new(sub { chdir $pwd });
57             chdir $workdir
58             or die "failed to change directory to:$workdir:$!";
59             my $installer = $installer_class->new(
60             url => $url,
61             root_files => \@root_files,
62             );
63             $installer->build($self);
64             $installer->test($self);
65             $installer->install($self)
66             if $self->opt_install;
67             }
68             }
69              
70             sub fetch_all {
71             my ($self, $base_url, $dir, $subdir, $files, $fetched) = @_;
72             $fetched ||= {};
73             for my $f (@$files) {
74             if ($f =~ m|/$|) {
75             my $d = $`;
76             mkdir "$dir/$subdir$d"
77             or die "failed to create dir:$dir/$subdir$d:$!";
78             $self->fetch_all(
79             $base_url,
80             $dir,
81             "$subdir$f",
82             [ $self->files_from_dir("$base_url$subdir$f") ],
83             $fetched,
84             );
85             } elsif (! $fetched->{"$subdir$f"}) {
86             print "$subdir$f\n";
87             my $r = LWP::Simple::mirror("$base_url$subdir$f", "$dir/$subdir$f");
88             die "failed to fetch URL:$base_url$subdir$f, got $r"
89             unless $r == 200;
90             chmod 0755, "$dir/$subdir$f"
91             or die "failed to set chmod +x on file:$dir/$subdir/$f:$!";
92             $fetched->{"$subdir$f"} = 1;
93             }
94             }
95             }
96              
97             sub files_from_dir {
98             my ($self, $url) = @_;
99            
100             my $body = LWP::Simple::get($url)
101             or die "failed to fetch URL:$url";
102             return grep {
103             $_ !~ m{^(\.{1,2}|)$},
104             } map {
105             substr($_, 0, length $url) eq $url ? (substr $_, length $url) : ()
106             } map {
107             my ($tag, %attr) = @$_;
108             $tag eq 'a' && $attr{href} ? (uri_unescape $attr{href}) : ();
109             } do {
110             my $lx = HTML::LinkExtor->new(undef, $url);
111             $lx->parse($body);
112             $lx->links;
113             };
114             }
115              
116             sub register {
117             my ($klass, $installer) = @_;
118             push @Installers, $installer;
119             }
120              
121             1;