File Coverage

blib/lib/STF/Dispatcher/Impl/File.pm
Criterion Covered Total %
statement 93 97 95.8
branch 23 32 71.8
condition 3 5 60.0
subroutine 22 22 100.0
pod 0 12 0.0
total 141 168 83.9


line stmt bran cond sub pod time code
1             package STF::Dispatcher::Impl::File;
2 1     1   1883 use strict;
  1         2  
  1         38  
3 1     1   6 use HTTP::Date ();
  1         2  
  1         13  
4 1     1   1060 use File::Copy ();
  1         3104  
  1         24  
5 1     1   9 use File::Temp ();
  1         2  
  1         19  
6 1     1   6 use File::Spec;
  1         2  
  1         18  
7 1     1   6 use File::Path ();
  1         2  
  1         16  
8 1     1   948 use Plack::MIME;
  1         888  
  1         49  
9             use Class::Accessor::Lite
10 1         12 ro => [ qw(buckets storage_path) ]
11 1     1   7 ;
  1         1  
12              
13             sub new {
14 1     1 0 17 my ($class, %args) = @_;
15              
16 1   33     12 $args{storage_path} ||= File::Temp::tempdir( CLEANUP => 1 );
17              
18 1         128898 bless{ buckets => {}, %args }, $class;
19             }
20              
21 30     30 0 270 sub start_request {}
22             sub create_bucket {
23 2     2 0 17 my ($self, $args) = @_;
24 2         12 my $dir = File::Spec->catdir( $self->storage_path, $args->{bucket_name} );
25 2 50       46 if ( ! -d $dir ) {
26 2 50       499 if (! File::Path::make_path( $dir, { mode => 0755 } ) ) {
27 0         0 Carp::croak( "Failed to create $dir: $!" );
28             }
29             }
30 2         9 return 1;
31             }
32              
33             sub get_bucket {
34 31     31 0 265 my ($self, $args) = @_;
35 31         933 my $dir = File::Spec->catdir( $self->storage_path, $args->{bucket_name} );
36 31 100       1979 return $dir if -d $dir;
37             }
38              
39             sub delete_bucket {
40 1     1 0 199 my ($self, $args) = @_;
41 1         4 my $dir = $args->{bucket};
42 1         1600 return File::Path::remove_tree( $dir );
43             }
44              
45             sub create_object {
46 3     3 0 6036 my ($self, $args) = @_;
47 3         11 my $input = $args->{input};
48 3         10 my $content = $args->{content};
49 3         71 my $file = File::Spec->catfile( $args->{bucket}, $args->{object_name} );
50 3         792 my $dir = File::Basename::dirname( $file );
51 3 100       747 if (! -d $dir ) {
52 1 50       1664 if (! File::Path::make_path( $dir, { mode => 0755 } ) ) {
53 0         0 Carp::croak( "Failed to create directory $dir: $!" );
54             }
55             }
56              
57 3 50       617 open my $fh, '>', $file or
58             Carp::croak( "Failed to open file $file for writing: $!" );
59 3 50       13 print $fh $input ? do { local $/; <$input> } : $content;
  3         20  
  3         99  
60 3         863 close ($fh);
61              
62 3         27 1;
63             }
64              
65             sub is_valid_object {
66 6     6 0 60 my ($self, $args) = @_;
67 6         67 my $file = File::Spec->catfile( $args->{bucket}, $args->{object_name} );
68 6         166 return -f $file;
69             }
70              
71             sub get_object {
72 9     9 0 1966 my ($self, $args) = @_;
73 9         105 my $file = File::Spec->catfile( $args->{bucket}, $args->{object_name} );
74 9 100       311 return unless -f $file;
75              
76 6         221 my @stat = stat($file);
77 6 100       181 if ( my $ims = $args->{request}->header('if-modified-since') ) {
78 2 100       161 if ( $stat[9] > HTTP::Date::str2time( $ims ) ) {
79 1         79 return STF::Dispatcher::PSGI::HTTPException->throw( 304, [], [] );
80             }
81             }
82              
83 5 50       508 open my $fh, '<', $file
84             or Carp::croak("Failed to open file $file for reading: $!");
85              
86             return STF::Dispatcher::Impl::File::Object->new(
87             modified_on => $stat[9],
88             content_type => Plack::MIME->mime_type($file) || 'text/plain',
89 5   100     51 content => do { local $/; <$fh> },
  5         95  
  5         284  
90             );
91             }
92              
93             sub modify_object {
94 1     1 0 233 return 1;
95             }
96              
97             sub delete_object {
98 1     1 0 11 my ($self, $args) = @_;
99 1         12 my $file = File::Spec->catfile( $args->{bucket}, $args->{object_name} );
100 1 50       33 return unless -f $file;
101 1         178 unlink $file;
102             }
103              
104             sub rename_bucket {
105 2     2 0 17 my ($self, $args) = @_;
106              
107 2         3 my $bucket = $args->{bucket};
108 2         5 my $name = $args->{name};
109 2         12 my $source = File::Spec->catdir($bucket);
110 2         8 my $destination = File::Spec->catdir($self->storage_path, $name);
111 2 100       67 if (-e $destination) {
112 1         11 return;
113             }
114 1         8 File::Copy::move( $source, $destination );
115             }
116              
117             sub rename_object {
118 2     2 0 25 my ($self, $args) = @_;
119              
120 2         24 my $source = File::Spec->catfile( $args->{source_bucket}, $args->{source_object_name} );
121 2         18 my $dest = File::Spec->catfile( $args->{destination_bucket}, $args->{destination_object_name } );
122 2         91 my $dir = File::Basename::dirname( $dest );
123 2 100       63 if (! -d $dir ) {
124 1 50       372 if (! File::Path::make_path( $dir, { mode => 0755 } ) ) {
125 0         0 Carp::croak( "Failed to create directory $dir: $!" );
126             }
127             }
128              
129 2 50       25 if (! File::Copy::move( $source, $dest )) {
130 0         0 Carp::croak("Failed to move from '$source' to '$dest': $!");
131             }
132              
133 2         314 return 1;
134             }
135              
136             package
137             STF::Dispatcher::Impl::File::Object;
138 1     1   1377 use strict;
  1         2  
  1         44  
139             use Class::Accessor::Lite
140 1         16 new => 1,
141             ro => [ qw(content_type content modified_on) ]
142 1     1   5 ;
  1         2  
143              
144             1;
145              
146              
147             __END__