File Coverage

blib/lib/OTRS/OPM/Installer.pm
Criterion Covered Total %
statement 102 144 70.8
branch 26 54 48.1
condition 12 33 36.3
subroutine 14 20 70.0
pod 0 2 0.0
total 154 253 60.8


line stmt bran cond sub pod time code
1             package OTRS::OPM::Installer;
2             $OTRS::OPM::Installer::VERSION = '0.05';
3             # ABSTRACT: Install OTRS add ons
4              
5 2     2   107729 use v5.10;
  2         18  
6              
7 2     2   12 use strict;
  2         3  
  2         41  
8 2     2   10 use warnings;
  2         3  
  2         51  
9              
10 2     2   676 use Moo;
  2         12057  
  2         13  
11 2     2   3025 use IO::All;
  2         26424  
  2         19  
12 2     2   1427 use Capture::Tiny qw(:all);
  2         43604  
  2         297  
13 2     2   1299 use Types::Standard qw(ArrayRef Str Bool);
  2         161503  
  2         22  
14              
15 2     2   3424 use OTRS::OPM::Parser;
  2         446016  
  2         89  
16              
17 2     2   1308 use OTRS::OPM::Installer::Types;
  2         6  
  2         91  
18 2     2   1018 use OTRS::OPM::Installer::Utils::OTRS;
  2         7  
  2         74  
19 2     2   14 use OTRS::OPM::Installer::Utils::File;
  2         6  
  2         39  
20 2     2   10 use OTRS::OPM::Installer::Logger;
  2         3  
  2         3324  
21              
22             has package => ( is => 'ro', isa => Str );
23             has otrs_version => ( is => 'ro', isa => Str, lazy => 1, default => \&_build_otrs_version );
24             has prove => ( is => 'ro', default => sub { 0 } );
25             has manager => ( is => 'ro', lazy => 1, default => \&_build_manager );
26             has repositories => ( is => 'ro', isa => ArrayRef[Str] );
27             has conf => ( is => 'ro' );
28             has force => ( is => 'ro', isa => Bool );
29             has sudo => ( is => 'ro', isa => Bool );
30             has utils_otrs => ( is => 'ro', lazy => 1, default => sub{ OTRS::OPM::Installer::Utils::OTRS->new } );
31             has verbose => ( is => 'ro', isa => Bool, default => sub { 0 } );
32             has logger => ( is => 'ro', lazy => 1, default => sub { OTRS::OPM::Installer::Logger->new } );
33              
34             sub list_available {
35 0     0 0 0 my ( $self, %params ) = @_;
36              
37 0         0 my %file_opts;
38 0 0 0     0 if ( $params{repositories} and ref $params{repositories} eq 'ARRAY' ) {
39 0         0 $file_opts{repositories} = $params{repositories};
40             }
41              
42 0         0 my $package_utils = OTRS::OPM::Installer::Utils::File->new(
43             %file_opts,
44             package => 'DummyPackage', # ::File needs a package set
45             otrs_version => $self->otrs_version,
46             );
47              
48 0         0 return $package_utils->list_available;
49             }
50              
51             sub install {
52 5     5 0 3183 my $self = shift;
53              
54 5 50       24 if ( @_ % 2 ) {
55 5         26 unshift @_, 'package';
56             }
57              
58 5         15 my %params = @_;
59              
60 5         9 my %file_opts;
61 5 50       26 if ( $self->repositories ) {
62 5         13 $file_opts{repositories} = $self->repositories;
63             }
64              
65 5 50 33     14 if ( $params{repositories} and ref $params{repositories} eq 'ARRAY' ) {
66 0         0 $file_opts{repositories} = $params{repositories};
67             }
68              
69 5         9 my $version_string = "";
70 5 0 33     15 if ( $params{version} and $params{version_exact} ) {
71 0         0 $file_opts{version} = $params{version};
72 0         0 $version_string = $params{version};
73             }
74              
75 5 50 0     17 say sprintf "Try to install %s %s...", $params{package} || $self->package, $version_string if $self->verbose;
76            
77 5   33     130 my $installed_version = $self->utils_otrs->is_installed( package => $params{package} || $self->package );
78 5 100       104 if ( $installed_version ) {
79             my $message = sprintf 'Addon %s is installed (%s)',
80 1   33     7 $params{package} || $self->package, $installed_version;
81              
82 1         19 $self->logger->debug( message => $message );
83 1         66 say $message;
84              
85 1 50       11 if ( $params{version} ) {
86             my $check = $self->utils_otrs->_check_version(
87             installed => $installed_version,
88             requested => $params{version},
89 0         0 );
90              
91 0 0       0 return 1 if $check;
92             }
93             }
94              
95             my $package_utils = OTRS::OPM::Installer::Utils::File->new(
96             %file_opts,
97 5   33     106 package => $params{package} || $self->package,
98             otrs_version => $self->otrs_version,
99             verbose => $self->verbose,
100             );
101              
102 5         11109 my $package_path = $package_utils->resolve_path;
103              
104 5 100       45 if ( !$package_path ) {
105             my $message = sprintf "Could not find a .opm file for %s%s (OTRS version %s)",
106             $params{package} || $self->package,
107 1 50 33     37 ( $file_opts{version} ? " $file_opts{version}" : "" ),
108             $self->otrs_version;
109              
110 1         28 $self->logger->error( fatal => $message );
111 1         57 say $message;
112 1         11 return;
113             }
114              
115 4         100 my $parsed = OTRS::OPM::Parser->new(
116             opm_file => $package_path,
117             );
118              
119 4         8880 $parsed->parse;
120              
121 4 100       20426 if ( $parsed->error_string ) {
122 1         35 my $message = sprintf "Cannot parse $package_path: %s", $parsed->error_string;
123 1         31 $self->logger->error( fatal => $message );
124 1         73 say $message;
125 1         13 return;
126             }
127              
128 3 50       73 if ( !$self->_check_matching_versions( $parsed, $self->otrs_version ) ) {
129 0         0 my $message = sprintf 'framework versions of %s (%s) doesn\'t match otrs version %s',
130             $parsed->name,
131             join ( ', ', $parsed->framework ),
132             $self->otrs_version;
133              
134 0         0 $self->logger->error( fatal => $message );
135 0         0 say $message;
136 0         0 return;
137             }
138              
139 3 100       64 if ( $self->utils_otrs->is_installed( package => $parsed->name, version => $parsed->version ) ) {
140 2         153 my $message = sprintf 'Addon %s is up to date (%s)',
141             $parsed->name, $parsed->version;
142              
143 2         93 $self->logger->debug( message => $message );
144 2         127 say $message;
145 2         153 return 1;
146             }
147              
148 1 50       69 say sprintf "Working on %s...", $parsed->name if $self->verbose;
149 1         21 $self->logger->debug( message => sprintf "Working on %s...", $parsed->name );
150              
151 1 50       45 my @dependencies = @{ $parsed->dependencies || [] };
  1         20  
152 1         17 my @cpan_deps = grep{ $_->{type} eq 'CPAN' }@dependencies;
  0         0  
153 1         3 my @otrs_deps = grep{ $_->{type} eq 'OTRS' }@dependencies;
  0         0  
154              
155 1         6 my $found_dependencies = join ', ', map{ $_->{name} }@dependencies;
  0         0  
156 1 50       5 say sprintf "Found dependencies: %s", $found_dependencies if $self->verbose;
157 1         19 $self->logger->debug( message => sprintf "Found dependencies: %s", $found_dependencies );
158              
159 1         31 for my $cpan_dep ( @cpan_deps ) {
160 0         0 my $module = $cpan_dep->{name};
161 0         0 my $version = $cpan_dep->{version};
162              
163 0 0       0 eval "use $module $version; 1;" and next;
164              
165 0         0 $self->_cpan_install( %{$cpan_dep} );
  0         0  
166             }
167              
168 1         4 for my $otrs_dep ( @otrs_deps ) {
169 0         0 my $module = $otrs_dep->{name};
170 0         0 my $version = $otrs_dep->{version};
171              
172 0 0       0 $self->utils_otrs->is_installed( %{$otrs_dep} ) and next;
  0         0  
173              
174 0         0 my $success = $self->install( package => $module, version => $version );
175 0 0 0     0 if ( !$success && !$self->force ) {
176 0         0 return;
177             }
178             }
179              
180 1 50       9 if ( $self->prove ) {
181             # TODO: run unittests
182             }
183              
184 1         8 my $content = io( $package_path )->slurp;
185              
186 1         701 my $message = sprintf "Install %s ...", $parsed->name;
187 1 50       72 say $message if $self->verbose;
188 1         20 $self->logger->debug( message => $message );
189              
190 1         37 $self->manager->PackageInstall( String => $content );
191              
192 1         41 return 1;
193             }
194              
195             sub _cpan_install {
196 0     0   0 my ( $self, %params) = @_;
197              
198 0         0 my $dist = $params{name};
199 0 0       0 my @sudo = $self->sudo ? 'sudo' : ();
200             my ($out, $err, $exit) = capture {
201 0     0   0 system @sudo, 'cpanm', $dist;
202 0         0 };
203              
204 0 0       0 if ( $out !~ m{Successfully installed } ) {
205 0         0 die "Installation of dependency failed ($dist)! - ($err)";
206             }
207              
208 0         0 return;
209             }
210              
211             sub _build_manager {
212 0     0   0 my $self = shift;
213              
214 0         0 return $self->utils_otrs->manager;
215             }
216              
217             sub _build_utils_otrs {
218 0     0   0 OTRS::OPM::Installer::Utils::OTRS->new;
219             }
220              
221             sub _build_otrs_version {
222 0     0   0 shift->utils_otrs->otrs_version;
223             }
224              
225             sub _check_matching_versions {
226 11     11   250 my ($self, $parsed, $otrs_version) = @_;
227              
228 11         41 my ($major, $minor, $patch) = split /\./, $otrs_version;
229              
230 11         20 my $check_ok;
231              
232             FRAMEWORK:
233 11         17 for my $required_framework ( @{ $parsed->framework } ) {
  11         66  
234 29         169 my ($r_major, $r_minor, $r_patch) = split /\./, $required_framework;
235              
236 29 100       78 next FRAMEWORK if $r_major != $major;
237 22 100 100     91 next FRAMEWORK if lc $r_minor ne 'x' && $r_minor != $minor;
238 8 100 100     36 next FRAMEWORK if lc $r_patch ne 'x' && $r_patch != $patch;
239              
240 6         12 $check_ok = 1;
241 6         11 last FRAMEWORK;
242             }
243              
244 11         46 return $check_ok;
245             }
246              
247             1;
248              
249             __END__