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