887013b914296c7cd22437c41c36a41539097c56
[kivitendo-erp.git] / scripts / installation_check.pl
1 #!/usr/bin/perl -w
2
3 our $master_templates;
4 BEGIN {
5   use FindBin;
6
7   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
8   push   (@INC, $FindBin::Bin . '/..');                  # '.' will be removed from @INC soon.
9
10   # this is a default dir. may be wrong in your installation, change it then
11   $master_templates = $FindBin::Bin . '/../templates/print/';
12 }
13
14 use strict;
15 use Getopt::Long;
16 use List::MoreUtils qw(uniq);
17 use Pod::Usage;
18 use Term::ANSIColor;
19 use Text::Wrap;
20
21 unless (eval { require Config::Std; 1 }){
22   print STDERR <<EOL ;
23 +------------------------------------------------------------------------------+
24   Perl Modul Config::Std could not be loaded.
25
26   Debian: you may install the needed *.deb package with:
27     apt-get install libconfig-std-perl
28
29   Red Hat/Fedora/CentOS: you may install the needed *.rpm package with:
30     yum install perl-Config-Std
31
32   SUSE: you may install the needed *.rpm package with:
33     zypper install perl-Config-Std
34
35 +------------------------------------------------------------------------------+
36 EOL
37
38   exit 72;
39 }
40
41 use SL::InstallationCheck;
42 use SL::LxOfficeConf;
43
44 my @missing_modules;
45 my %check;
46 Getopt::Long::Configure ("bundling");
47 GetOptions(
48   "v|verbose"   => \ my $v,
49   "a|all"       => \ $check{a},
50   "o|optional!" => \ $check{o},
51   "d|devel!"    => \ $check{d},
52   "l|latex!"    => \ $check{l},
53   "r|required!" => \ $check{r},
54   "h|help"      => sub { pod2usage(-verbose => 2) },
55   "c|color!"    => \ ( my $c = 1 ),
56   "i|install-command!"  => \ my $apt,
57   "s|silent"    => \ $check{s},
58 );
59
60 my %install_methods = (
61   apt    => { key => 'debian', install => 'sudo apt install', system => "Debian, Ubuntu" },
62   yum    => { key => 'fedora', install => 'sudo yum install',     system => "RHEL, Fedora, CentOS" },
63   zypper => { key => 'suse',   install => 'sudo zypper install',  system => "SLES, openSUSE" },
64   cpan   => { key => 'name',   install => "sudo cpan",            system => "CPAN" },
65 );
66
67 # if nothing is requested check "required"
68 my $default_run;
69 if (!defined $check{a}
70  && !defined $check{l}
71  && !defined $check{o}
72  && !defined $check{d}) {
73   $check{r} = 1;
74   $default_run ='1';  # no parameter, therefore print a note after default run
75 }
76
77 if ($check{a}) {
78   $check{$_} //= 1 for qw(o d l r);
79 }
80
81
82 $| = 1;
83
84 if (!SL::LxOfficeConf->read(undef, 'may fail')) {
85   print_header('Could not load the config file. If you have dependancies from any features enabled in the configuration these will still show up as optional because of this. Please rerun this script after installing the dependancies needed to load the configuration.')
86 } else {
87   SL::InstallationCheck::check_for_conditional_dependencies();
88 }
89
90 if ($check{r}) {
91   print_header('Checking Required Modules');
92   check_module($_, required => 1) for @SL::InstallationCheck::required_modules;
93   check_pdfinfo();
94 }
95 if ($check{o}) {
96   print_header('Checking Optional Modules');
97   check_module($_, optional => 1) for @SL::InstallationCheck::optional_modules;
98   check_aqbanking();
99 }
100 if ($check{d}) {
101   print_header('Checking Developer Modules');
102   check_module($_, devel => 1) for @SL::InstallationCheck::developer_modules;
103 }
104 if ($check{l}) {
105   check_latex();
106 }
107
108 my $fail = @missing_modules;
109 print_header('Result');
110 print_line('All', $fail ? 'NOT ok' : 'OK', $fail ? 'red' : 'green');
111
112 if ($default_run && !$check{s}) {
113   if (@missing_modules) {
114     $apt = 1;
115   print <<"EOL";
116
117 HEY! It seems there are modules MISSING! Look for the red lines with "NOT ok"
118 above. You'll want to fix those, I've enabled --install-command for you...
119 EOL
120   } else {
121   print <<"EOL";
122
123 Standard check done, everything is OK and up to date. Have a look at the --help
124 section of this script to see some more advanced checks for developer and
125 optional dependancies, as well as LaTeX packages you might need.
126 EOL
127   }
128 }
129
130 if (@missing_modules && $apt && !$check{s}) {
131   print "\nHere are some sample installation lines, choose one appropriate for your system:\n\n";
132   local $Text::Wrap::separator = " \\\n";
133
134   for (keys %install_methods) {
135     my $method = $install_methods{$_};
136     if (my @install_candidates = grep $_, map { $_->{$method->{key}} } @missing_modules) {
137       print "$method->{system}:\n";
138       print wrap("  ", "    ",  $method->{install}, @install_candidates);
139       print $/;
140     }
141   }
142 }
143
144 exit !!@missing_modules;
145
146 sub check_latex {
147   my ($res) = check_kpsewhich();
148   print_result("Looking for LaTeX kpsewhich", $res);
149   if ($res) {
150     check_template_dir($_) for SL::InstallationCheck::template_dirs($master_templates);
151   }
152 }
153
154 sub check_template_dir {
155   my ($dir) = @_;
156   my $path  = $master_templates . $dir;
157
158   print_header("Checking LaTeX Dependencies for Master Templates '$dir'");
159   kpsewhich($path, 'cls', $_) for SL::InstallationCheck::classes_from_latex($path, '\documentclass');
160
161   my @sty = sort { $a cmp $b } uniq (
162     SL::InstallationCheck::classes_from_latex($path, '\usepackage'),
163     qw(textcomp ulem pdfx embedfile)
164   );
165   kpsewhich($path, 'sty', $_) for @sty;
166 }
167
168 our $mastertemplate_path = './templates/print/';
169
170 sub check_kpsewhich {
171   return 1 if SL::InstallationCheck::check_kpsewhich();
172
173   print STDERR <<EOL if $v && !$check{s};
174 +------------------------------------------------------------------------------+
175   Can't find kpsewhich, is there a proper installed LaTeX?
176   On Debian you may run "aptitude install texlive-base-bin"
177 +------------------------------------------------------------------------------+
178 EOL
179   return 0;
180 }
181
182 sub kpsewhich {
183   my ($dw, $type, $package) = @_;
184   $package =~ s/[^-_0-9A-Za-z]//g;
185   my $type_desc = $type eq 'cls' ? 'document class' : 'package';
186
187   eval { require String::ShellQuote; 1 } or warn "can't load String::ShellQuote" && return;
188      $dw         = String::ShellQuote::shell_quote $dw;
189   my $e_package  = String::ShellQuote::shell_quote $package;
190   my $e_type     = String::ShellQuote::shell_quote $type;
191
192   my $exit = system(qq|TEXINPUTS=".:$dw:" kpsewhich $e_package.$e_type > /dev/null|);
193   my $res  = $exit > 0 ? 0 : 1;
194
195   print_result("Looking for LaTeX $type_desc $package", $res);
196   if (!$res) {
197     print STDERR <<EOL if $v && !$check{s};
198 +------------------------------------------------------------------------------+
199   LaTeX $type_desc $package could not be loaded.
200
201   On Debian you may find the needed *.deb package with:
202     apt-file search $package.$type
203
204   Maybe you need to install apt-file first by:
205     aptitude install apt-file && apt-file update
206 +------------------------------------------------------------------------------+
207 EOL
208   }
209 }
210
211 sub check_pdfinfo {
212   my $line = "Looking for pdfinfo executable";
213   my $shell_out = `pdfinfo -v 2>&1 | grep version 2> /dev/null`;
214   my ($label,$vers,$ver_string)  = split / /,$shell_out;
215   if ( $label && $label eq 'pdfinfo' ) {
216     chop $ver_string;
217     print_line($line, $ver_string, 'green');
218   } else {
219     print_line($line, 'not installed','red');
220     my %modinfo = ( debian => 'poppler-utils' );
221     push @missing_modules, \%modinfo;
222
223   }
224 }
225
226 sub check_aqbanking {
227   my $aqbin = $::lx_office_conf{applications}->{aqbanking};
228   if ( !$aqbin ) {
229     print_line('Looking for aqbanking executable', 'not configured','red');
230   }
231   else {
232     my $line = "Looking for aqbanking executable '".$aqbin."'";
233     my $shell_out = `$aqbin versions 2>&1 | grep AqBanking-CLI 2> /dev/null`;
234     my ($label,$version)  = split /:/,$shell_out;
235     if ( $label && $label eq ' AqBanking-CLI' ) {
236       chop $version;
237       print_line($line, $version, 'green');
238     } else {
239       print_line($line, 'not installed','red');
240       my %modinfo = ( name => 'aqbanking' );
241       push @missing_modules, \%modinfo;
242     }
243   }
244 }
245
246 sub check_module {
247   my ($module, %role) = @_;
248
249   my $line = "Looking for $module->{fullname}";
250   $line   .= " (from $module->{dist_name})" if $module->{dist_name};
251   my ($res, $ver) = SL::InstallationCheck::module_available($module->{"name"}, $module->{version});
252   if ($res) {
253     my $ver_string = ref $ver && $ver->can('numify') ? $ver->numify : $ver ? $ver : 'no version';
254     print_line($line, $ver_string, 'green');
255   } else {
256     print_result($line, $res);
257   }
258
259
260   return if $res;
261
262   push @missing_modules, $module;
263
264   my $needed_text =
265       $role{optional} ? 'It is OPTIONAL for kivitendo but RECOMMENDED for improved functionality.'
266     : $role{required} ? 'It is NEEDED by kivitendo and must be installed.'
267     : $role{devel}    ? 'It is OPTIONAL for kivitendo and only useful for developers.'
268     :                   'It is not listed as a dependancy yet. Please tell this the developers.';
269
270   my @source_texts = module_source_texts($module);
271   local $" = $/;
272   print STDERR <<EOL if $v && !$check{s};
273 +------------------------------------------------------------------------------+
274   $module->{fullname} could not be loaded.
275
276   This module is either too old or not available on your system.
277   $needed_text
278
279   Here are some ideas how to get it:
280
281 @source_texts
282 +------------------------------------------------------------------------------+
283 EOL
284 }
285
286 sub module_source_texts {
287   my ($module) = @_;
288   my @texts;
289   for my $key (keys %install_methods) {
290     my $method = $install_methods{$key};
291     push @texts, <<"EOL" if $module->{$method->{key}};
292   - Using $method->{system} you can install it with $key:
293       $method->{install} $module->{$method->{key}}
294 EOL
295   }
296   push @texts, <<EOL if $module->{url};
297   - You can download it from this URL and install it manually:
298       $module->{url}
299 EOL
300
301   return @texts;
302 }
303
304 sub mycolor {
305   return $_[0] unless $c;
306   return colored(@_);
307 }
308
309 sub print_result {
310   my ($test, $exit) = @_;
311   if ($exit) {
312     print_line($test, 'ok', 'green');
313   } else {
314     print_line($test, 'NOT ok', 'red');
315   }
316 }
317
318 sub print_line {
319   my ($text, $res, $color) = @_;
320   return if $check{s};
321   print $text, " ", ('.' x (78 - length($text) - length($res))), " ", mycolor($res, $color), $/;
322 }
323
324 sub print_header {
325   return if $check{s};
326   print $/;
327   print "$_[0]:", $/;
328 }
329
330 1;
331
332 __END__
333
334 =encoding UTF-8
335
336 =head1 NAME
337
338 scripts/installation_check.pl - check kivitendo dependancies
339
340 =head1 SYNOPSIS
341
342   scripts/installation_check.pl [OPTION]
343
344 =head1 DESCRIPTION
345
346 Check dependencys. List all perl modules needed by kivitendo, probes for them,
347 and warns if one is not available.  List all LaTeX document classes and
348 packages needed by kivitendo master templates, probes for them, and warns if
349 one is not available.
350
351
352 =head1 OPTIONS
353
354 =over 4
355
356 =item C<-a, --all>
357
358 Probe for all perl modules and all LaTeX master templates.
359
360 =item C<-c, --color>
361
362 Color output. Default on.
363
364 =item C<--no-color>
365
366 No color output. Helpful to avoid terminal escape problems.
367
368 =item C<-d, --devel>
369
370 Probe for perl developer dependancies. (Used for console  and tags file)
371
372 =item C<--no-devel>
373
374 Don't probe for perl developer dependancies. (Useful in combination with --all)
375
376 =item C<-h, --help>
377
378 Display this help.
379
380 =item C<-o, --optional>
381
382 Probe for optional modules.
383
384 =item C<--no-optional>
385
386 Don't probe for optional perl modules. (Useful in combination with --all)
387
388 =item C<-r, --required>
389
390 Probe for required perl modules (default).
391
392 =item C<--no-required>
393
394 Don't probe for required perl modules. (Useful in combination with --all)
395
396 =item C<-l. --latex>
397
398 Probe for LaTeX documentclasses and packages in master templates.
399
400 =item C<--no-latex>
401
402 Don't probe for LaTeX document classes and packages in master templates. (Useful in combination with --all)
403
404 =item C<-v. --verbose>
405
406 Print additional info for missing dependancies
407
408 =item C<-i, --install-command>
409
410 Tries to generate installation commands for the most common package managers.
411 Note that these lists can be slightly off, but it should still save you a lot
412 of typing.
413
414 =back
415
416 =head1 BUGS, CAVEATS and TODO
417
418 =over 4
419
420 =item *
421
422 Fedora packages not listed yet.
423
424 =item *
425
426 Not possible yet to generate a combined cpan/apt-get string to install all needed.
427
428 =item *
429
430 Not able to handle devel cpan modules yet.
431
432 =item *
433
434 Version requirements not fully tested yet.
435
436 =back
437
438 =head1 AUTHOR
439
440   Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
441   Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
442   Wulf Coulmann E<lt>wulf@coulmann.deE<gt>
443
444 =cut