File Coverage

blib/lib/App/Docker/Client.pm
Criterion Covered Total %
statement 52 90 57.7
branch 10 22 45.4
condition 7 14 50.0
subroutine 16 22 72.7
pod 10 10 100.0
total 95 158 60.1


line stmt bran cond sub pod time code
1             package App::Docker::Client;
2              
3             =head1 NAME
4              
5             App::Docker::Client - Simple and plain Docker client!
6              
7             =head1 VERSION
8              
9             Version 0.010100
10              
11             =cut
12              
13             our $VERSION = '0.010100';
14              
15 3     3   44459 use 5.16.0;
  3         9  
16 3     3   12 use strict;
  3         5  
  3         57  
17 3     3   9 use warnings;
  3         7  
  3         81  
18 3     3   1867 use LWP::UserAgent;
  3         103788  
  3         84  
19 3     3   1833 use JSON;
  3         29782  
  3         13  
20 3     3   1948 use LWP::Protocol::http::SocketUnixAlt;
  3         115856  
  3         1941  
21              
22             =head2 new
23              
24             Constructor
25              
26             =cut
27              
28             sub new {
29 2     2 1 181461 my $class = shift;
30 2         8 my $self = {@_};
31 2         12 $self->{_scheme_postfixes} = { file => ':', http => '://', https => '://', };
32 2         28 $self->{_valid_codes} = { 200 => 1, 201 => 1, 204 => 1 };
33 2         5 bless $self, $class;
34 2         4 return $self;
35             }
36              
37             =head1 SUBROUTINES/METHODS
38              
39             =cut
40              
41             =head2 authority
42              
43             Getter/Setter for internal hash key authority.
44             =cut
45              
46             sub authority {
47 4 100 100 4 1 26 return $_[0]->{authority} || '/var/run/docker.sock' unless $_[1];
48 1   50     4 $_[0]->{authority} = $_[1] || '/var/run/docker.sock';
49 1         3 return $_[0]->{authority};
50             }
51              
52             =head2 scheme
53              
54             Getter/Setter for internal hash key scheme.
55             =cut
56              
57             sub scheme {
58 5 100 100 5 1 330 return $_[0]->{scheme} || 'http' unless $_[1];
59 1   50     4 $_[0]->{scheme} = $_[1] || 'http';
60 1         3 return $_[0]->{scheme};
61             }
62              
63             =head2 json
64              
65             Getter/Setter for internal hash key json.
66             =cut
67              
68             sub json {
69 3 50 33 3 1 850 return $_[0]->{json} || JSON->new->utf8() unless $_[1];
70 0   0     0 $_[0]->{json} = $_[1] || JSON->new->utf8();
71 0         0 return $_[0]->{json};
72             }
73              
74             =head2 user_agent
75              
76             Getter/Setter for internal hash key UserAgent.
77              
78             =cut
79              
80             sub user_agent {
81 2     2 1 497 my ( $self, $user_agent ) = @_;
82 2 50       7 if ($user_agent) {
83 0         0 $self->{UserAgent} = $user_agent;
84 0         0 return $self->{UserAgent};
85             }
86 2 50       11 return $self->{UserAgent} if $self->{UserAgent};
87              
88 0 0       0 if ( -S $self->authority() ) {
89 0         0 LWP::Protocol::implementor( http => 'LWP::Protocol::http::SocketUnixAlt' );
90             }
91 0         0 $self->{UserAgent} = LWP::UserAgent->new();
92 0         0 return $self->{UserAgent};
93              
94             }
95              
96             =head2 get
97              
98              
99              
100             =cut
101              
102             sub get {
103 1     1 1 2 my ( $self, $path, $options ) = @_;
104 1         3 return $self->_to_hashref( $self->user_agent->get( $self->uri( $path, %$options ) ) );
105             }
106              
107             =head2 delete
108              
109              
110              
111             =cut
112              
113             sub delete {
114 0     0 1 0 my ( $self, $path, $options ) = @_;
115 0         0 return $self->_to_hashref( $self->user_agent->delete( $self->uri( $path, %$options ) ) );
116             }
117              
118              
119             =head2 request
120              
121             =cut
122              
123 0     0 1 0 sub request { $_[0]->_to_hashref( $_[0]->user_agent->request( $_[1] ) ) }
124              
125             =head2 post
126              
127             =cut
128              
129             sub post {
130 0     0 1 0 my ( $self, $path, $query, $body, $options ) = @_;
131 0 0       0 return $self->request( $self->_http_request( $path, $query ) ) unless $body;
132 0 0       0 return $self->request( $self->_handle_json( $path, $query, $body ) ) unless ($options);
133 0         0 return $self->request( $self->_handle_custom( $path, $query, $body, $options ) );
134             }
135              
136             =head2 uri
137              
138             Creating a new URI object.
139              
140             Internal varibales:
141            
142             * scheme
143            
144             * authority
145              
146             Given varibales:
147            
148             * path
149            
150             * query options
151              
152             =cut
153              
154             sub uri {
155 1     1 1 2 my ( $self, $path, %opts ) = @_;
156 1         6 require URI;
157             my $uri =
158             URI->new( $self->scheme()
159 1         3 . $self->{_scheme_postfixes}->{ lc $self->scheme() }
160             . $self->authority() . '/'
161             . $path );
162 1         4760 $uri->query_form(%opts);
163 1         51 return $uri;
164             }
165              
166             {
167              
168             =head2 post
169              
170             =cut
171              
172             sub _handle_json {
173 0     0   0 my ( $self, $path, $query, $body ) = @_;
174 0         0 my $req = $self->_http_request( $path, $query );
175 0         0 $req->content_type('application/json');
176 0         0 my $json = $self->json->encode($body);
177 0         0 $json =~ s/"(false|true)"/$1/g;
178 0         0 $req->content($json);
179 0         0 return $req;
180             }
181              
182             =head2 post
183              
184             =cut
185              
186             sub _handle_custom {
187 0     0   0 my ( $self, $path, $query, $body, $options ) = @_;
188 0         0 my $req = $self->_http_request( $path, $query );
189 0         0 $req->content_type( $options->{content_type} );
190             $req->content_length(
191 3     3   1645 do { use bytes; length $body }
  3         25  
  3         13  
  0         0  
  0         0  
192             );
193 0         0 $req->content($body);
194 0         0 return $req;
195             }
196              
197             =head2 _http_request
198              
199             create HTTP::Request by uri params
200              
201             =cut
202              
203             sub _http_request {
204 0     0   0 my ( $self, $path, $query ) = @_;
205 0         0 require HTTP::Request;
206 0         0 return HTTP::Request->new( POST => $self->uri( $path, %$query ) );
207             }
208              
209             =head2 _to_hashref
210              
211             Getter/Setter for internal hash key ua.
212              
213             =cut
214              
215             sub _to_hashref {
216 1     1   17072 my ( $self, $response ) = @_;
217 1         4 $self->_error_code( $response->code, $response->message, $response->content );
218 1         3 my $content = $response->content();
219 1 50       10 return if !$content;
220 1         2 my $data = eval { $self->json->decode($content) };
  1         5  
221 1 50       14 return $@ ? $content : $data;
222 0         0 require Carp;
223 0         0 Carp::cluck;
224 0         0 Carp::croak "JSON ERROR: $@";
225             }
226              
227             =head2 _error_code
228              
229             Simple error handler returns undef if everything is ok dies on error.
230              
231             =cut
232              
233             sub _error_code {
234 1     1   24 my ( $self, $code, $message, $content ) = @_;
235 1 50       7 return if $self->{_valid_codes}->{$code};
236 0           require Carp;
237 0           Carp::cluck;
238 0           Carp::croak "FAILURE: $code - " . qq~$message\n$content~;
239             }
240             }
241              
242             1; # End of App::Docker::Client
243              
244             __END__