140ecddc036e932664feb587165fc595630deda0
[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   push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
10
11   # this is a default dir. may be wrong in your installation, change it then
12   $master_templates = $FindBin::Bin . '/../templates/print/';
13 }
14
15 use strict;
16 use Getopt::Long;
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   kpsewhich($path, 'sty', $_) for SL::InstallationCheck::classes_from_latex($path, '\usepackage');
161 }
162
163 our $mastertemplate_path = './templates/print/';
164
165 sub check_kpsewhich {
166   return 1 if SL::InstallationCheck::check_kpsewhich();
167
168   print STDERR <<EOL if $v && !$check{s};
169 +------------------------------------------------------------------------------+
170   Can't find kpsewhich, is there a proper installed LaTeX?
171   On Debian you may run "aptitude install texlive-base-bin"
172 +------------------------------------------------------------------------------+
173 EOL
174   return 0;
175 }
176
177 sub kpsewhich {
178   my ($dw, $type, $package) = @_;
179   $package =~ s/[^-_0-9A-Za-z]//g;
180   my $type_desc = $type eq 'cls' ? 'document class' : 'package';
181
182   eval { require String::ShellQuote; 1 } or warn "can't load String::ShellQuote" && return;
183      $dw         = String::ShellQuote::shell_quote $dw;
184   my $e_package  = String::ShellQuote::shell_quote $package;
185   my $e_type     = String::ShellQuote::shell_quote $type;
186
187   my $exit = system(qq|TEXINPUTS=".:$dw:" kpsewhich $e_package.$e_type > /dev/null|);
188   my $res  = $exit > 0 ? 0 : 1;
189
190   print_result("Looking for LaTeX $type_desc $package", $res);
191   if (!$res) {
192     print STDERR <<EOL if $v && !$check{s};
193 +------------------------------------------------------------------------------+
194   LaTeX $type_desc $package could not be loaded.
195
196   On Debian you may find the needed *.deb package with:
197     apt-file search $package.$type
198
199   Maybe you need to install apt-file first by:
200     aptitude install apt-file && apt-file update
201 +------------------------------------------------------------------------------+
202 EOL
203   }
204 }
205
206 sub check_pdfinfo {
207   my $line = "Looking for pdfinfo executable";
208   my $shell_out = `pdfinfo -v 2>&1 | grep version 2> /dev/null`;
209   my ($label,$vers,$ver_string)  = split / /,$shell_out;
210   if ( $label && $label eq 'pdfinfo' ) {
211     chop $ver_string;
212     print_line($line, $ver_string, 'green');
213   } else {
214     print_line($line, 'not installed','red');
215     my %modinfo = ( debian => 'poppler-utils' );
216     push @missing_modules, \%modinfo;
217
218   }
219 }
220
221 sub check_aqbanking {
222   my $aqbin = $::lx_office_conf{applications}->{aqbanking};
223   if ( !$aqbin ) {
224     print_line('Looking for aqbanking executable', 'not configured','red');
225   }
226   else {
227     my $line = "Looking for aqbanking executable '".$aqbin."'";
228     my $shell_out = `$aqbin versions 2>&1 | grep AqBanking-CLI 2> /dev/null`;
229     my ($label,$version)  = split /:/,$shell_out;
230     if ( $label && $label eq ' AqBanking-CLI' ) {
231       chop $version;
232       print_line($line, $version, 'green');
233     } else {
234       print_line($line, 'not installed','red');
235       my %modinfo = ( name => 'aqbanking' );
236       push @missing_modules, \%modinfo;
237     }
238   }
239 }
240
241 sub check_module {
242   my ($module, %role) = @_;
243
244   my $line = "Looking for $module->{fullname}";
245   $line   .= " (from $module->{dist_name})" if $module->{dist_name};
246   my ($res, $ver) = SL::InstallationCheck::module_available($module->{"name"}, $module->{version});
247   if ($res) {
248     my $ver_string = ref $ver && $ver->can('numify') ? $ver->numify : $ver ? $ver : 'no version';
249     print_line($line, $ver_string, 'green');
250   } else {
251     print_result($line, $res);
252   }
253
254
255   return if $res;
256
257   push @missing_modules, $module;
258
259   my $needed_text =
260       $role{optional} ? 'It is OPTIONAL for kivitendo but RECOMMENDED for improved functionality.'
261     : $role{required} ? 'It is NEEDED by kivitendo and must be installed.'
262     : $role{devel}    ? 'It is OPTIONAL for kivitendo and only useful for developers.'
263     :                   'It is not listed as a dependancy yet. Please tell this the developers.';
264
265   my @source_texts = module_source_texts($module);
266   local $" = $/;
267   print STDERR <<EOL if $v && !$check{s};
268 +------------------------------------------------------------------------------+
269   $module->{fullname} could not be loaded.
270
271   This module is either too old or not available on your system.
272   $needed_text
273
274   Here are some ideas how to get it:
275
276 @source_texts
277 +------------------------------------------------------------------------------+
278 EOL
279 }
280
281 sub module_source_texts {
282   my ($module) = @_;
283   my @texts;
284   for my $key (keys %install_methods) {
285     my $method = $install_methods{$key};
286     push @texts, <<"EOL" if $module->{$method->{key}};
287   - Using $method->{system} you can install it with $key:
288       $method->{install} $module->{$method->{key}}
289 EOL
290   }
291   push @texts, <<EOL if $module->{url};
292   - You can download it from this URL and install it manually:
293       $module->{url}
294 EOL
295
296   return @texts;
297 }
298
299 sub mycolor {
300   return $_[0] unless $c;
301   return colored(@_);
302 }
303
304 sub print_result {
305   my ($test, $exit) = @_;
306   if ($exit) {
307     print_line($test, 'ok', 'green');
308   } else {
309     print_line($test, 'NOT ok', 'red');
310   }
311 }
312
313 sub print_line {
314   my ($text, $res, $color) = @_;
315   return if $check{s};
316   print $text, " ", ('.' x (78 - length($text) - length($res))), " ", mycolor($res, $color), $/;
317 }
318
319 sub print_header {
320   return if $check{s};
321   print $/;
322   print "$_[0]:", $/;
323 }
324
325 1;
326
327 __END__
328
329 =encoding UTF-8
330
331 =head1 NAME
332
333 scripts/installation_check.pl - check kivitendo dependancies
334
335 =head1 SYNOPSIS
336
337   scripts/installation_check.pl [OPTION]
338
339 =head1 DESCRIPTION
340
341 Check dependencys. List all perl modules needed by kivitendo, probes for them,
342 and warns if one is not available.  List all LaTeX document classes and
343 packages needed by kivitendo master templates, probes for them, and warns if
344 one is not available.
345
346
347 =head1 OPTIONS
348
349 =over 4
350
351 =item C<-a, --all>
352
353 Probe for all perl modules and all LaTeX master templates.
354
355 =item C<-c, --color>
356
357 Color output. Default on.
358
359 =item C<--no-color>
360
361 No color output. Helpful to avoid terminal escape problems.
362
363 =item C<-d, --devel>
364
365 Probe for perl developer dependancies. (Used for console  and tags file)
366
367 =item C<--no-devel>
368
369 Don't probe for perl developer dependancies. (Useful in combination with --all)
370
371 =item C<-h, --help>
372
373 Display this help.
374
375 =item C<-o, --optional>
376
377 Probe for optional modules.
378
379 =item C<--no-optional>
380
381 Don't probe for optional perl modules. (Useful in combination with --all)
382
383 =item C<-r, --required>
384
385 Probe for required perl modules (default).
386
387 =item C<--no-required>
388
389 Don't probe for required perl modules. (Useful in combination with --all)
390
391 =item C<-l. --latex>
392
393 Probe for LaTeX documentclasses and packages in master templates.
394
395 =item C<--no-latex>
396
397 Don't probe for LaTeX document classes and packages in master templates. (Useful in combination with --all)
398
399 =item C<-v. --verbose>
400
401 Print additional info for missing dependancies
402
403 =item C<-i, --install-command>
404
405 Tries to generate installation commands for the most common package managers.
406 Note that these lists can be slightly off, but it should still save you a lot
407 of typing.
408
409 =back
410
411 =head1 BUGS, CAVEATS and TODO
412
413 =over 4
414
415 =item *
416
417 Fedora packages not listed yet.
418
419 =item *
420
421 Not possible yet to generate a combined cpan/apt-get string to install all needed.
422
423 =item *
424
425 Not able to handle devel cpan modules yet.
426
427 =item *
428
429 Version requirements not fully tested yet.
430
431 =back
432
433 =head1 AUTHOR
434
435   Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
436   Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
437   Wulf Coulmann E<lt>wulf@coulmann.deE<gt>
438
439 =cut