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   8048 use 5.008;
  6         21  
  6         248  
4              
5 6     6   37 use strict;
  6         15  
  6         199  
6 6     6   33 use warnings;
  6         12  
  6         259  
7              
8 6     6   34 use base qw{ CPAN::Access::AdHoc::Archive };
  6         13  
  6         595  
9              
10 6     6   7597 use Archive::Tar ();
  6         754766  
  6         196  
11 6     6   72 use CPAN::Access::AdHoc::Util qw{ :carp __guess_media_type };
  6         16  
  6         1132  
12 6     6   40 use File::Spec::Unix ();
  6         13  
  6         138  
13 6     6   5710 use HTTP::Date ();
  6         10954  
  6         150  
14 6     6   43 use IO::File ();
  6         12  
  6         86  
15 6     6   38 use IO::Uncompress::Bunzip2 ();
  6         12  
  6         87  
16 6     6   34 use IO::Uncompress::Gunzip ();
  6         10  
  6         8254  
17              
18             our $VERSION = '0.000_18';
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 1057 my ( $class, %arg ) = @_;
35              
36 8   33     67 my $self = bless {}, ref $class || $class;
37              
38 8         76 my $archive = Archive::Tar->new();
39              
40 8         167 $self->archive( $archive );
41              
42 8 50       47 if ( defined( my $content = delete $arg{content} ) ) {
43              
44 8 50       35 if ( my $encoding = delete $arg{encoding} ) {
    0          
45 8 50       37 $decode{$encoding}
46             or __wail( "Unsupported encoding '$encoding'" );
47 8         31 $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     13163 ref $content
54             or defined $arg{path}
55             or $arg{path} = $content;
56              
57 8         79 $archive->read( $content );
58              
59             }
60              
61 8         35970 $self->mtime( delete $arg{mtime} );
62 8         66 $self->path( delete $arg{path} );
63              
64 8         139 return $self;
65             }
66              
67             }
68              
69             sub base_directory {
70 45     45 1 641 my ( $self ) = @_;
71              
72 135 50       750 my @rslt = sort { length $a <=> length $b || $a cmp $b }
  135         1260  
73 405         4700 map { _construct_name( $_ ) }
74 45         158 grep { $_->is_dir() }
75             $self->archive()->get_files();
76              
77 45 50       127 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         65 my $base = $rslt[0];
84 45 100 33     356 defined $base
      66        
85             and '' ne $base
86             and $base !~ m{ / \z }smx
87             and $base .= '/';
88              
89 45         145 return $base;
90             }
91              
92             sub extract {
93 1     1 1 1814 my ( $self ) = @_;
94              
95 1         13 $self->archive()->extract();
96              
97 1         5 return $self;
98             }
99              
100             sub get_item_content {
101 29     29 1 3724 my ( $self, $file ) = @_;
102 29         63 $file = $self->base_directory() . $file;
103 29         97 return $self->archive()->get_content( $file );
104             }
105              
106             sub get_item_mtime {
107 1     1 1 876 my ( $self, $file ) = @_;
108 1         5 $file = $self->base_directory() . $file;
109 1         5 my @files = $self->archive()->get_files( $file );
110             @files
111 1 50       119 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   30 my ( $class, $rslt ) = @_;
121              
122 13 100       47 $handled{ $rslt->header( 'Content-Type' ) }
123             or return;
124              
125 8         331 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 6 my ( $self, $name ) = @_;
138 3         13 $name = $self->base_directory() . $name;
139 3         33 return $self->archive()->contains_file( $name );
140             }
141              
142             sub list_contents {
143 6     6 1 68 my ( $self ) = @_;
144              
145 6         10 my @rslt;
146              
147 6         33 my $base = $self->base_directory();
148 6         136 $base = qr{ \A \Q$base\E }smx;
149              
150 6         27 foreach my $file ( $self->archive()->get_files() ) {
151 54 100       368 $file->is_file()
152             or next;
153 36         424 my $name = _construct_name( $file );
154 36 50       456 $name =~ s/ $base //smx
155             or next;
156 36         87 push @rslt, $name;
157             }
158              
159 6         51 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 14 my ( $self, $fn ) = @_;
170 2 50       16 if ( ! defined $fn ) {
171 2         13 $fn = ( File::Spec->splitpath( $self->path() ) )[2];
172             }
173 2         21 my $resp = HTTP::Response->new();
174 2         132 __guess_media_type( $resp, $fn );
175 2         7 my $encoding = $resp->header( 'Content-Encoding' );
176 2 50       71 defined $encoding
177             or $encoding = '';
178 2         14 my @args = ( $fn );
179 2 50 33     17 if ( defined $encoding && '' ne $encoding ) {
180 2 50       7 exists $known_encoding{$encoding}
181             or __wail( "Encoding $encoding not supported" );
182 2         6 push @args, $known_encoding{$encoding};
183             }
184 2         13 $self->archive()->write( @args );
185 2         16719 return $self;
186             }
187             }
188              
189             sub _construct_name {
190 171     171   228 my ( $file ) = @_;
191 171         379 my $prefix = $file->prefix();
192 171 100 66     1728 if ( defined $prefix && '' ne $prefix ) {
193 44 50       126 $prefix =~ m{ / \z }smx
194             or $prefix .= '/';
195 44         107 return $prefix . $file->name();
196             } else {
197 127         294 return $file->name();
198             }
199             }
200              
201             1;
202              
203             __END__