File Coverage

blib/lib/CPAN/Access/AdHoc/Archive/Tar.pm
Criterion Covered Total %
statement 100 105 95.2
branch 21 40 52.5
condition 8 18 44.4
subroutine 21 21 100.0
pod 8 8 100.0
total 158 192 82.2


line stmt bran cond sub pod time code
1             package CPAN::Access::AdHoc::Archive::Tar;
2              
3 6     6   4527 use 5.008;
  6         14  
  6         204  
4              
5 6     6   26 use strict;
  6         9  
  6         159  
6 6     6   31 use warnings;
  6         7  
  6         231  
7              
8 6     6   24 use base qw{ CPAN::Access::AdHoc::Archive };
  6         6  
  6         504  
9              
10 6     6   4112 use Archive::Tar ();
  6         425023  
  6         198  
11 6     6   54 use CPAN::Access::AdHoc::Util qw{ :carp __guess_media_type };
  6         10  
  6         1036  
12 6     6   32 use File::Spec::Unix ();
  6         9  
  6         84  
13 6     6   3407 use HTTP::Date ();
  6         7972  
  6         135  
14 6     6   36 use IO::File ();
  6         7  
  6         83  
15 6     6   23 use IO::Uncompress::Bunzip2 ();
  6         8  
  6         66  
16 6     6   26 use IO::Uncompress::Gunzip ();
  6         9  
  6         5560  
17              
18             our $VERSION = '0.000_194';
19              
20             {
21              
22             my %decode = (
23             gzip => sub {
24             my ( $content ) = @_;
25             return IO::Uncompress::Gunzip->new( $content );
26             },
27             'x-bzip2' => sub {
28             my ( $content ) = @_;
29             return IO::Uncompress::Bunzip2->new( $content );
30             },
31             );
32              
33             sub new {
34 8     8 1 775 my ( $class, %arg ) = @_;
35              
36 8   33     65 my $self = bless {}, ref $class || $class;
37              
38 8         66 my $archive = Archive::Tar->new();
39              
40 8         131 $self->archive( $archive );
41              
42 8 50       33 if ( defined( my $content = delete $arg{content} ) ) {
43              
44 8 50       25 if ( my $encoding = delete $arg{encoding} ) {
    0          
45 8 50       21 $decode{$encoding}
46             or __wail( "Unsupported encoding '$encoding'" );
47 8         26 $content = $decode{$encoding}->( $content );
48             } elsif ( ref $content ) {
49 0 0       0 $content = IO::File->new( $content, '<' )
50             or __wail( "Unable to open string reference: $!" );
51             }
52              
53 8 50 33     10196 ref $content
54             or defined $arg{path}
55             or $arg{path} = $content;
56              
57 8         34 $archive->read( $content );
58              
59             }
60              
61 8         22675 $self->mtime( delete $arg{mtime} );
62 8         44 $self->path( delete $arg{path} );
63              
64 8         85 return $self;
65             }
66              
67             }
68              
69             sub base_directory {
70 45     45 1 380 my ( $self ) = @_;
71              
72 135 50       553 my @rslt = sort { length $a <=> length $b || $a cmp $b }
  135         865  
73 405         2952 map { _construct_name( $_ ) }
74 45         118 grep { $_->is_dir() }
75             $self->archive()->get_files();
76              
77 45 50       95 if ( ! @rslt ) {
78 0 0       0 @rslt = sort { length $a <=> length $b || $a cmp $b }
  0         0  
79 0         0 map { ( File::Spec::Unix->splitpath( _construct_name( $_ ) ) )[1] }
80             $self->archive()->get_files();
81             }
82              
83 45         48 my $base = $rslt[0];
84 45 100 33     316 defined $base
      66        
85             and '' ne $base
86             and $base !~ m{ / \z }smx
87             and $base .= '/';
88              
89 45         105 return $base;
90             }
91              
92             sub extract {
93 1     1 1 1103 my ( $self ) = @_;
94              
95 1         8 $self->archive()->extract();
96              
97 1         4 return $self;
98             }
99              
100             sub get_item_content {
101 29     29 1 2475 my ( $self, $file ) = @_;
102 29         52 $file = $self->base_directory() . $file;
103 29         72 return $self->archive()->get_content( $file );
104             }
105              
106             sub get_item_mtime {
107 1     1 1 477 my ( $self, $file ) = @_;
108 1         3 $file = $self->base_directory() . $file;
109 1         6 my @files = $self->archive()->get_files( $file );
110             @files
111 1 50       67 and return $files[0]->mtime();
112 0         0 return;
113             }
114              
115             {
116              
117             my %handled = map { $_ => 1 } qw{ application/x-tar };
118              
119             sub __handle_http_response {
120 13     13   24 my ( $class, $rslt ) = @_;
121              
122 13 100       34 $handled{ $rslt->header( 'Content-Type' ) }
123             or return;
124              
125 8         230 return $class->new(
126             content => \( scalar $rslt->content() ),
127             encoding => scalar $rslt->header( 'Content-Encoding' ),
128             mtime => HTTP::Date::str2time(
129             scalar $rslt->header( 'Last-Modified' ) ),
130             path => scalar $rslt->header( 'Content-Location' ),
131             );
132             }
133              
134             }
135              
136             sub item_present {
137 3     3 1 7 my ( $self, $name ) = @_;
138 3         21 $name = $self->base_directory() . $name;
139 3         11 return $self->archive()->contains_file( $name );
140             }
141              
142             sub list_contents {
143 6     6 1 52 my ( $self ) = @_;
144              
145 6         8 my @rslt;
146              
147 6         11 my $base = $self->base_directory();
148 6         103 $base = qr{ \A \Q$base\E }smx;
149              
150 6         19 foreach my $file ( $self->archive()->get_files() ) {
151 54 100       245 $file->is_file()
152             or next;
153 36         303 my $name = _construct_name( $file );
154 36 50       454 $name =~ s/ $base //smx
155             or next;
156 36         61 push @rslt, $name;
157             }
158              
159 6         45 return @rslt;
160             }
161              
162             {
163             my %known_encoding = (
164             'gzip' => Archive::Tar->COMPRESS_GZIP(),
165             'x-bzip2' => Archive::Tar->COMPRESS_BZIP(),
166             );
167              
168             sub write : method { ## no critic (ProhibitBuiltInHomonyms)
169 2     2 1 9 my ( $self, $fn ) = @_;
170 2 50       5 if ( ! defined $fn ) {
171 2         7 $fn = ( File::Spec->splitpath( $self->path() ) )[2];
172             }
173 2         13 my $resp = HTTP::Response->new();
174 2         82 __guess_media_type( $resp, $fn );
175 2         6 my $encoding = $resp->header( 'Content-Encoding' );
176 2 50       68 defined $encoding
177             or $encoding = '';
178 2         11 my @args = ( $fn );
179 2 50 33     13 if ( defined $encoding && '' ne $encoding ) {
180 2 50       7 exists $known_encoding{$encoding}
181             or __wail( "Encoding $encoding not supported" );
182 2         5 push @args, $known_encoding{$encoding};
183             }
184 2         7 $self->archive()->write( @args );
185 2         25513 return $self;
186             }
187             }
188              
189             sub _construct_name {
190 171     171   145 my ( $file ) = @_;
191 171         236 my $prefix = $file->prefix();
192 171 100 66     1248 if ( defined $prefix && '' ne $prefix ) {
193 44 50       105 $prefix =~ m{ / \z }smx
194             or $prefix .= '/';
195 44         68 return $prefix . $file->name();
196             } else {
197 127         189 return $file->name();
198             }
199             }
200              
201             1;
202              
203             __END__