File Coverage

blib/lib/OPM/Repository/Source.pm
Criterion Covered Total %
statement 116 118 98.3
branch 43 50 86.0
condition 5 9 55.5
subroutine 15 15 100.0
pod 2 2 100.0
total 181 194 93.3


line stmt bran cond sub pod time code
1             package OPM::Repository::Source;
2              
3 10     10   482551 use v5.10;
  10         83  
4              
5             # ABSTRACT: Parser for a single {otrs|otobo}.xml file
6              
7 10     10   45 use strict;
  10         20  
  10         192  
8 10     10   38 use warnings;
  10         15  
  10         373  
9              
10             our $VERSION = '1.0.0'; # VERSION
11              
12 10     10   2517 use Moo;
  10         50878  
  10         49  
13 10     10   12555 use HTTP::Tiny;
  10         334972  
  10         350  
14 10     10   3943 use HTTP::Tiny::FileProtocol;
  10         226530  
  10         355  
15 10     10   5270 use XML::LibXML;
  10         311374  
  10         62  
16 10     10   4522 use Regexp::Common qw(URI);
  10         12284  
  10         67  
17              
18             our $ALLOWED_SCHEME = [ 'HTTP', 'file' ];
19              
20             has url => ( is => 'ro', required => 1, isa => \&_check_uri );
21             has content => ( is => 'ro', lazy => 1, builder => \&_get_content );
22             has tree => ( is => 'ro', lazy => 1, builder => \&_build_tree );
23             has error => ( is => 'rwp' );
24             has packages => ( is => 'rwp', default => sub { {} }, isa => sub { die "No hashref" unless ref $_[0] eq 'HASH' } );
25             has parsed => ( is => 'rwp', predicate => 1 );
26             has product => ( is => 'ro', default => sub { 'otrs' } );
27              
28             sub find {
29 26     26 1 3596 my ($self, %params) = @_;
30              
31 26 100       74 return if !exists $params{name};
32 23 50       55 return if !exists $params{framework};
33              
34 23         35 my $package = $params{name};
35 23         33 my $framework = $params{framework};
36              
37 23 50 33     103 if ( !defined $package || !defined $framework ) {
38 0         0 return;
39             }
40              
41 23 100       76 if ( !$self->has_parsed ) {
42 7         28 $self->_parse( %params );
43             }
44              
45 23         8751 my %packages = %{ $self->packages };
  23         232  
46              
47 23 100       85 return if !$packages{$package};
48 16 100       71 return if !$packages{$package}->{$framework};
49              
50 8   66     44 my $wanted = $params{version} || $packages{$package}->{$framework}->{latest};
51 8         49 return $packages{$package}->{$framework}->{versions}->{$wanted};
52             }
53              
54             sub list {
55 8     8 1 3684 my ($self, %params) = @_;
56              
57 8 100       38 if ( !$self->has_parsed ) {
58 4         18 $self->_parse( %params );
59             }
60              
61 8         4393 my %packages = %{ $self->packages };
  8         100  
62 8         22 my $framework = $params{framework};
63              
64 8         62 my @package_names = sort keys %packages;
65              
66 8 100       26 if ( $framework ) {
67 4         12 @package_names = grep{ $packages{$_}->{$framework} }@package_names;
  48         85  
68             }
69              
70 8 100       20 if ( $params{details} ) {
71 4         5 my @package_list;
72              
73             NAME:
74 4         7 for my $name ( @package_names ) {
75 36 50       51 my @all_framework_versions = $framework ? $framework : keys %{ $packages{$name} || {} };
  24 100       72  
76              
77             OPM_VERSION:
78 36         44 for my $framework_version ( @all_framework_versions ) {
79              
80             VERSION:
81 98 50       96 for my $version ( keys %{ $packages{$name}->{$framework_version}->{versions} || {} } ) {
  98         293  
82             push @package_list, {
83             name => $name,
84             version => $version,
85 258         755 url => $packages{$name}->{$framework_version}->{versions}->{$version},
86             }
87             }
88             }
89             }
90              
91 4 50       22 @package_names = sort { $a->{name} cmp $b->{name} || $a->{version} cmp $b->{version} } @package_list;
  950         1234  
92             }
93              
94 8         57 return @package_names;
95             }
96              
97             sub _check_uri {
98 11 100   11   164 my @allowed_schemes = ref $ALLOWED_SCHEME ? @{ $ALLOWED_SCHEME } : $ALLOWED_SCHEME;
  9         31  
99              
100 11         20 my $matches;
101              
102             SCHEME:
103 11         26 for my $scheme ( @allowed_schemes ) {
104             my $regex = ( lc $scheme eq 'http' ) ?
105             $RE{URI}{HTTP}{-scheme => qr/https?/} :
106 17 100       1646 $RE{URI}{$scheme};
107              
108 17 100       996 if ( $_[0] =~ m{\A$regex\z} ) {
109 11         1998 $matches++;
110 11         48 last SCHEME;
111             }
112             }
113              
114 11 50       81 die "No valid URI" unless $matches;
115 11         200 return 1;
116             }
117              
118             sub _parse {
119 11     11   32 my ($self, %params) = @_;
120              
121 11 100       199 return if !$self->tree;
122              
123 10         56 my %packages = %{ $self->packages };
  10         65  
124              
125 10         302 my @repo_packages = $self->tree->findnodes( 'Package' );
126 10         2490 my $base_url = $self->url;
127 10         86 $base_url =~ s{\w+\.xml\z}{};
128              
129             REPO_PACKAGE:
130 10         31 for my $repo_package ( @repo_packages ) {
131 2458         27641 my $name = $repo_package->findvalue( 'Name' );
132 2458         122791 my @frameworks = $repo_package->findnodes( 'Framework' );
133 2458         43723 my $file = $repo_package->findvalue( 'File' );
134              
135 2458         105775 my $version = $repo_package->findvalue( 'Version' );
136              
137             FRAMEWORK:
138 2458         107636 for my $framework ( @frameworks ) {
139 3402         9355 my $framework_version = $framework->textContent;
140 3402         10338 my $short_version = join '.', (split /\./, $framework_version, 3)[0..1];
141 3402         6976 my $saved_version = $packages{$name}->{$short_version}->{latest};
142              
143 3402         5532 my $minimum = $framework->findvalue('@Minimum');
144 3402         111677 my $maximum = $framework->findvalue('@Maximum');
145              
146 3402 100       102432 if ( !$saved_version ) {
    100          
147 541         4221 $packages{$name}->{$short_version} = {
148             latest => $version,
149             min_versions => {
150             },
151             max_versions => {
152             },
153             versions => {
154             $version => sprintf "%s%s", $base_url, $file,
155             },
156             };
157             }
158             elsif ( $self->_version_is_newer( $version, $saved_version ) ) {
159 290         531 $packages{$name}->{$short_version}->{latest} = $version;
160 290         1466 $packages{$name}->{$short_version}->{versions}->{$version} =
161             sprintf "%s%s", $base_url, $file;
162             }
163             else {
164 2571         12833 $packages{$name}->{$short_version}->{versions}->{$version} =
165             sprintf "%s%s", $base_url, $file;
166             }
167             }
168             }
169              
170 10         133 $self->_set_parsed( 1 );
171 10         348 $self->_set_packages( \%packages );
172              
173 10         91 return 1;
174             }
175              
176             sub _version_is_newer {
177 2861     2861   3900 my ($self, $new, $old) = @_;
178              
179 2861         7060 my @new_levels = split /\./, $new;
180 2861         5144 my @old_levels = split /\./, $old;
181              
182 2861 50       6281 for my $i ( 0 .. ( $#new_levels > $#old_levels ? @new_levels : @old_levels ) ) {
183 6197 100 66     17508 if ( !$old_levels[$i] || $new_levels[$i] > $old_levels[$i] ) {
    100          
184 290         647 return 1;
185             }
186             elsif ( $new_levels[$i] < $old_levels[$i] ) {
187 2571         5224 return 0;
188             }
189             }
190              
191 0         0 return 1;
192             }
193              
194             sub _get_content {
195 8     8   303 my $self = shift;
196 8         60 my $res = HTTP::Tiny->new->get( $self->url );
197              
198 8         6330 $self->_set_error( undef );
199            
200 8 100       28 if ( $res->{success} ) {
201 7         53 return $res->{content};
202             }
203              
204 1         3 $self->_set_error( $res->{reason} );
205              
206 1         12 return sprintf '<%s_packages>', ( $self->product ) x 2;
207             }
208              
209             sub _build_tree {
210 11     11   120 my $self = shift;
211              
212 11         43 $self->_set_error( undef );
213              
214 11         13 my $tree;
215 11 100       19 eval {
216 11         88 my $parser = XML::LibXML->new->parse_string( $self->content );
217 10         69511 $tree = $parser->getDocumentElement;
218             } or $self->_set_error( $@ );
219              
220 11         647 return $tree;
221             }
222              
223             1;
224              
225             __END__