1#!/usr/local/bin/perl 2# -- 3# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 4# -- 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.txt. 17# -- 18 19use strict; 20use warnings; 21 22use File::Basename; 23use FindBin qw($RealBin); 24use lib dirname($RealBin); 25use lib dirname($RealBin) . '/Kernel/cpan-lib'; 26use lib dirname($RealBin) . '/Custom'; 27 28use Kernel::System::Environment; 29use Kernel::System::VariableCheck qw( :all ); 30 31use ExtUtils::MakeMaker; 32use File::Path; 33use Getopt::Long; 34use Term::ANSIColor; 35 36our %InstTypeToCMD = ( 37 38 # [InstType] => { 39 # CMD => '[cmd to install module]', 40 # UseModule => 1/0, 41 # } 42 # Set UseModule to 1 if you want to use the 43 # cpan module name of the package as replace string. 44 # e.g. yum install "perl(Date::Format)" 45 # If you set it 0 it will use the name 46 # for the InstType of the module 47 # e.g. apt-get install -y libtimedate-perl 48 # and as fallback the default cpan install command 49 # e.g. cpan DBD::Oracle 50 aptget => { 51 CMD => 'apt-get install -y %s', 52 UseModule => 0, 53 }, 54 emerge => { 55 CMD => 'emerge %s', 56 UseModule => 0, 57 }, 58 ppm => { 59 CMD => 'ppm install %s', 60 UseModule => 0, 61 }, 62 yum => { 63 CMD => 'yum install "%s"', 64 SubCMD => 'perl(%s)', 65 UseModule => 1, 66 }, 67 zypper => { 68 CMD => 'zypper install %s', 69 UseModule => 0, 70 }, 71 ports => { 72 CMD => 'cd /usr/ports %s', 73 SubCMD => ' && make -C %s install clean', 74 UseModule => 0, 75 }, 76 default => { 77 CMD => 'cpan %s', 78 }, 79); 80 81our %DistToInstType = ( 82 83 # apt-get 84 debian => 'aptget', 85 ubuntu => 'aptget', 86 87 # emerge 88 # for reasons unknown, some environments return "gentoo" (incl. the quotes) 89 '"gentoo"' => 'emerge', 90 gentoo => 'emerge', 91 92 # yum 93 centos => 'yum', 94 fedora => 'yum', 95 rhel => 'yum', 96 redhat => 'yum', 97 98 # zypper 99 suse => 'zypper', 100 101 # FreeBSD 102 freebsd => 'ports', 103); 104 105our $OSDist; 106eval { 107 require Linux::Distribution; ## nofilter(TidyAll::Plugin::OTRS::Perl::Require) 108 import Linux::Distribution; 109 $OSDist = Linux::Distribution::distribution_name() || ''; 110}; 111if ( !defined $OSDist ) { 112 $OSDist = $^O; 113} 114 115my $AllModules; 116my $PackageList; 117my $Help; 118GetOptions( 119 all => \$AllModules, 120 list => \$PackageList, 121 h => \$Help 122); 123 124# check needed params 125if ($Help) { 126 print "\nReturn all required and optional packages of OTRS.\n\n"; 127 print "Usage:\n"; 128 print " otrs.CheckModules.pl [-list|all]\n\n"; 129 print "Options:\n"; 130 printf " %-22s - %s", '[-list]', 'Return an install command with all required packages.' . "\n"; 131 printf " %-22s - %s", '[-all]', 'Return all required, optional and bundled packages of OTRS.' . "\n\n"; 132 exit 1; 133} 134 135my $Options = shift || ''; 136my $NoColors; 137 138if ( $ENV{nocolors} || $Options =~ m{\A nocolors}msxi ) { 139 $NoColors = 1; 140} 141 142my $ExitCode = 0; # success 143 144# config 145my @NeededModules = ( 146 { 147 Module => 'Apache::DBI', 148 Required => 0, 149 Comment => 'Improves Performance on Apache webservers with mod_perl enabled.', 150 InstTypes => { 151 aptget => 'libapache-dbi-perl', 152 emerge => 'dev-perl/Apache-DBI', 153 zypper => 'perl-Apache-DBI', 154 ports => 'www/p5-Apache-DBI', 155 }, 156 }, 157 { 158 Module => 'Apache2::Reload', 159 Required => 0, 160 Comment => 'Avoids web server restarts on mod_perl.', 161 InstTypes => { 162 aptget => 'libapache2-mod-perl2', 163 emerge => 'dev-perl/Apache-Reload', 164 zypper => 'apache2-mod_perl', 165 ports => 'www/mod_perl2', 166 }, 167 }, 168 { 169 Module => 'Archive::Tar', 170 Required => 1, 171 Comment => 'Required for compressed file generation (in perlcore).', 172 InstTypes => { 173 emerge => 'perl-core/Archive-Tar', 174 zypper => 'perl-Archive-Tar', 175 ports => 'archivers/p5-Archive-Tar', 176 }, 177 }, 178 { 179 Module => 'Archive::Zip', # required for OTRSBusiness 180 Required => 1, 181 Comment => 'Required for compressed file generation.', 182 InstTypes => { 183 aptget => 'libarchive-zip-perl', 184 emerge => 'dev-perl/Archive-Zip', 185 zypper => 'perl-Archive-Zip', 186 ports => 'archivers/p5-Archive-Zip', 187 }, 188 }, 189 { 190 Module => 'Crypt::Eksblowfish::Bcrypt', 191 Required => 0, 192 Comment => 'For strong password hashing.', 193 InstTypes => { 194 aptget => 'libcrypt-eksblowfish-perl', 195 emerge => 'dev-perl/Crypt-Eksblowfish', 196 zypper => 'perl-Crypt-Eksblowfish', 197 ports => 'security/p5-Crypt-Eksblowfish', 198 }, 199 }, 200 { 201 Module => 'Date::Format', 202 Required => 1, 203 InstTypes => { 204 aptget => 'libtimedate-perl', 205 emerge => 'dev-perl/TimeDate', 206 zypper => 'perl-TimeDate', 207 ports => 'devel/p5-TimeDate', 208 }, 209 }, 210 { 211 Module => 'DateTime', 212 Required => 1, 213 InstTypes => { 214 aptget => 'libdatetime-perl', 215 emerge => 'dev-perl/DateTime', 216 zypper => 'perl-DateTime', 217 ports => 'devel/p5-TimeDate', 218 }, 219 Depends => [ 220 { 221 Module => 'DateTime::TimeZone', 222 Comment => 'Olson time zone database, required for correct time calculations.', 223 VersionsRecommended => [ 224 { 225 Version => '2.20', 226 Comment => 'This version includes recent time zone changes for Chile.', 227 }, 228 ], 229 }, 230 ], 231 }, 232 { 233 Module => 'DBI', 234 Required => 1, 235 InstTypes => { 236 aptget => 'libdbi-perl', 237 emerge => 'dev-perl/DBI', 238 zypper => 'perl-DBI', 239 ports => 'databases/p5-DBI', 240 }, 241 }, 242 { 243 Module => 'DBD::mysql', 244 Required => 0, 245 Comment => 'Required to connect to a MySQL database.', 246 InstTypes => { 247 aptget => 'libdbd-mysql-perl', 248 emerge => 'dev-perl/DBD-mysql', 249 zypper => 'perl-DBD-mysql', 250 ports => 'databases/p5-DBD-mysql', 251 }, 252 }, 253 { 254 Module => 'DBD::ODBC', 255 Required => 0, 256 VersionsNotSupported => [ 257 { 258 Version => '1.23', 259 Comment => 260 'This version is broken and not useable! Please upgrade to a higher version.', 261 }, 262 ], 263 Comment => 'Required to connect to a MS-SQL database.', 264 InstTypes => { 265 aptget => 'libdbd-odbc-perl', 266 emerge => undef, 267 yum => undef, 268 zypper => undef, 269 ports => 'databases/p5-DBD-ODBC', 270 }, 271 }, 272 { 273 Module => 'DBD::Oracle', 274 Required => 0, 275 Comment => 'Required to connect to a Oracle database.', 276 InstTypes => { 277 aptget => undef, 278 emerge => undef, 279 yum => undef, 280 zypper => undef, 281 ports => undef, 282 }, 283 }, 284 { 285 Module => 'DBD::Pg', 286 Required => 0, 287 Comment => 'Required to connect to a PostgreSQL database.', 288 InstTypes => { 289 aptget => 'libdbd-pg-perl', 290 emerge => 'dev-perl/DBD-Pg', 291 zypper => 'perl-DBD-Pg', 292 ports => 'databases/p5-DBD-Pg', 293 }, 294 }, 295 { 296 Module => 'Digest::SHA', # Supposed to be in perlcore, but seems to be missing on some distributions. 297 Required => 1, 298 InstTypes => { 299 aptget => 'libdigest-sha-perl', 300 emerge => 'dev-perl/Digest-SHA', 301 zypper => 'perl-Digest-SHA', 302 ports => 'security/p5-Digest-SHA' 303 }, 304 }, 305 { 306 Module => 'Encode::HanExtra', 307 VersionRequired => '0.23', 308 Required => 0, 309 Comment => 'Required to handle mails with several Chinese character sets.', 310 InstTypes => { 311 aptget => 'libencode-hanextra-perl', 312 emerge => 'dev-perl/Encode-HanExtra', 313 zypper => 'perl-Encode-HanExtra', 314 ports => 'chinese/p5-Encode-HanExtra', 315 }, 316 }, 317 { 318 Module => 'IO::Socket::SSL', 319 Required => 0, 320 Comment => 'Required for SSL connections to web and mail servers.', 321 VersionsRecommended => [ 322 { 323 Version => '2.066', 324 Comment => 'This version fixes email sending (bug#14357).', 325 }, 326 ], 327 InstTypes => { 328 aptget => 'libio-socket-ssl-perl', 329 emerge => 'dev-perl/IO-Socket-SSL', 330 zypper => 'perl-IO-Socket-SSL', 331 ports => 'security/p5-IO-Socket-SSL', 332 }, 333 }, 334 { 335 Module => 'JSON::XS', 336 Required => 0, 337 Comment => 'Recommended for faster AJAX/JavaScript handling.', 338 InstTypes => { 339 aptget => 'libjson-xs-perl', 340 emerge => 'dev-perl/JSON-XS', 341 zypper => 'perl-JSON-XS', 342 ports => 'converters/p5-JSON-XS', 343 }, 344 }, 345 { 346 Module => 'List::Util::XS', 347 Required => 1, 348 Comment => 349 "Do a 'force install Scalar::Util' via cpan shell to fix this problem. Please make sure to have an c compiler and make installed before.", 350 InstTypes => { 351 aptget => 'libscalar-list-utils-perl', 352 emerge => 'perl-core/Scalar-List-Utils', 353 zypper => 'perl-Scalar-List-Utils', 354 ports => 'lang/p5-Scalar-List-Utils', 355 }, 356 }, 357 { 358 Module => 'LWP::UserAgent', 359 Required => 1, 360 InstTypes => { 361 aptget => 'libwww-perl', 362 emerge => 'dev-perl/libwww-perl', 363 zypper => 'perl-libwww-perl', 364 ports => 'www/p5-libwww', 365 }, 366 }, 367 { 368 Module => 'Mail::IMAPClient', 369 VersionRequired => '3.22', 370 Comment => 'Required for IMAP TLS connections.', 371 Required => 0, 372 InstTypes => { 373 aptget => 'libmail-imapclient-perl', 374 emerge => 'dev-perl/Mail-IMAPClient', 375 zypper => 'perl-Mail-IMAPClient', 376 ports => 'mail/p5-Mail-IMAPClient', 377 }, 378 Depends => [ 379 { 380 Module => 'IO::Socket::SSL', 381 Required => 0, 382 Comment => 'Required for SSL connections to web and mail servers.', 383 VersionsRecommended => [ 384 { 385 Version => '2.066', 386 Comment => 'This version fixes email sending (bug#14357).', 387 }, 388 ], 389 InstTypes => { 390 aptget => 'libio-socket-ssl-perl', 391 emerge => 'dev-perl/IO-Socket-SSL', 392 zypper => 'perl-IO-Socket-SSL', 393 ports => 'security/p5-IO-Socket-SSL', 394 }, 395 }, 396 { 397 Module => 'Authen::SASL', 398 Required => 0, 399 Comment => 'Required for MD5 authentication mechanisms in IMAP connections.', 400 InstTypes => { 401 aptget => 'libauthen-sasl-perl', 402 emerge => 'dev-perl/Authen-SASL', 403 zypper => 'perl-Authen-SASL', 404 }, 405 }, 406 { 407 Module => 'Authen::NTLM', 408 Required => 0, 409 Comment => 'Required for NTLM authentication mechanism in IMAP connections.', 410 InstTypes => { 411 aptget => 'libauthen-ntlm-perl', 412 emerge => 'dev-perl/Authen-NTLM', 413 zypper => 'perl-Authen-NTLM', 414 }, 415 }, 416 ], 417 }, 418 { 419 Module => 'ModPerl::Util', 420 Required => 0, 421 Comment => 'Improves Performance on Apache webservers dramatically.', 422 InstTypes => { 423 aptget => 'libapache2-mod-perl2', 424 emerge => 'www-apache/mod_perl', 425 zypper => 'apache2-mod_perl', 426 ports => 'www/mod_perl2', 427 }, 428 }, 429 { 430 Module => 'Moo', 431 Required => 1, 432 Comment => 'Required for random number generator.', 433 InstTypes => { 434 aptget => 'libmoo-perl', 435 emerge => 'dev-perl/Moo', 436 zypper => 'perl-Moo', 437 ports => 'devel/p5-Moo', 438 }, 439 }, 440 { 441 Module => 'Net::DNS', 442 Required => 1, 443 VersionsNotSupported => [ 444 { 445 Version => '0.60', 446 Comment => 447 'This version is broken and not useable! Please upgrade to a higher version.', 448 }, 449 ], 450 InstTypes => { 451 aptget => 'libnet-dns-perl', 452 emerge => 'dev-perl/Net-DNS', 453 zypper => 'perl-Net-DNS', 454 ports => 'dns/p5-Net-DNS', 455 }, 456 }, 457 { 458 Module => 'Net::LDAP', 459 Required => 0, 460 Comment => 'Required for directory authentication.', 461 InstTypes => { 462 aptget => 'libnet-ldap-perl', 463 emerge => 'dev-perl/perl-ldap', 464 zypper => 'perl-ldap', 465 ports => 'net/p5-perl-ldap', 466 }, 467 }, 468 { 469 Module => 'Net::SMTP', 470 Required => 0, 471 Comment => 'Simple Mail Transfer Protocol Client.', 472 VersionsRecommended => [ 473 { 474 Version => '3.11', 475 Comment => 'This version fixes email sending (bug#14357).', 476 }, 477 ], 478 InstTypes => { 479 aptget => undef, 480 emerge => undef, 481 zypper => undef, 482 ports => undef, 483 }, 484 }, 485 { 486 Module => 'Template', 487 Required => 1, 488 Comment => 'Template::Toolkit, the rendering engine of OTRS.', 489 InstTypes => { 490 aptget => 'libtemplate-perl', 491 emerge => 'dev-perl/Template-Toolkit', 492 zypper => 'perl-Template-Toolkit', 493 ports => 'www/p5-Template-Toolkit', 494 }, 495 }, 496 { 497 Module => 'Template::Stash::XS', 498 Required => 1, 499 Comment => 'The fast data stash for Template::Toolkit.', 500 InstTypes => { 501 aptget => 'libtemplate-perl', 502 emerge => 'dev-perl/Template-Toolkit', 503 zypper => 'perl-Template-Toolkit', 504 ports => 'www/p5-Template-Toolkit', 505 }, 506 }, 507 { 508 Module => 'Text::CSV_XS', 509 Required => 0, 510 Comment => 'Recommended for faster CSV handling.', 511 InstTypes => { 512 aptget => 'libtext-csv-xs-perl', 513 emerge => 'dev-perl/Text-CSV_XS', 514 zypper => 'perl-Text-CSV_XS', 515 ports => 'textproc/p5-Text-CSV_XS', 516 }, 517 }, 518 { 519 Module => 'Time::HiRes', 520 Required => 1, 521 Comment => 'Required for high resolution timestamps.', 522 InstTypes => { 523 aptget => 'perl', 524 emerge => 'perl-core/Time-HiRes', 525 zypper => 'perl-Time-HiRes', 526 ports => 'devel/p5-Time-HiRes', 527 }, 528 }, 529 { 530 Module => 'XML::LibXML', 531 Required => 1, 532 Comment => 'Required for XML processing.', 533 InstTypes => { 534 aptget => 'libxml-libxml-perl', 535 zypper => 'perl-XML-LibXML', 536 ports => 'textproc/p5-XML-LibXML', 537 }, 538 }, 539 { 540 Module => 'XML::LibXSLT', 541 Required => 0, 542 Comment => 'Required for Generic Interface XSLT mapping module.', 543 InstTypes => { 544 aptget => 'libxml-libxslt-perl', 545 zypper => 'perl-XML-LibXSLT', 546 ports => 'textproc/p5-XML-LibXSLT', 547 }, 548 }, 549 { 550 Module => 'XML::Parser', 551 Required => 0, 552 Comment => 'Recommended for XML processing.', 553 InstTypes => { 554 aptget => 'libxml-parser-perl', 555 emerge => 'dev-perl/XML-Parser', 556 zypper => 'perl-XML-Parser', 557 ports => 'textproc/p5-XML-Parser', 558 }, 559 }, 560 { 561 Module => 'YAML::XS', 562 Required => 1, 563 Comment => 'Required for fast YAML processing.', 564 565 # Example of how to use VersionsRecommended option. 566 # VersionsRecommended => [ 567 # { 568 # Version => '5.0.1', 569 # Comment => 'This version fixes a bug.', 570 # }, 571 # { 572 # Version => '6.0.1', 573 # Comment => 'This version fixes a critical issue.', 574 # }, 575 # ], 576 InstTypes => { 577 aptget => 'libyaml-libyaml-perl', 578 emerge => 'dev-perl/YAML-LibYAML', 579 zypper => 'perl-YAML-LibYAML', 580 ports => 'textproc/p5-YAML-LibYAML', 581 }, 582 }, 583); 584 585if ($PackageList) { 586 my %PackageList = _PackageList( \@NeededModules ); 587 588 if ( IsArrayRefWithData( $PackageList{Packages} ) ) { 589 590 my $CMD = $PackageList{CMD}; 591 592 for my $Package ( @{ $PackageList{Packages} } ) { 593 if ( $PackageList{SubCMD} ) { 594 $Package = sprintf $PackageList{SubCMD}, $Package; 595 } 596 } 597 printf $CMD, join( ' ', @{ $PackageList{Packages} } ); 598 print "\n"; 599 } 600} 601else { 602 # try to determine module version number 603 my $Depends = 0; 604 605 for my $Module (@NeededModules) { 606 _Check( $Module, $Depends, $NoColors ); 607 } 608 609 if ($AllModules) { 610 print "\nBundled modules:\n\n"; 611 612 my %PerlInfo = Kernel::System::Environment->PerlInfoGet( 613 BundledModules => 1, 614 ); 615 616 for my $Module ( sort keys %{ $PerlInfo{Modules} } ) { 617 _Check( 618 { 619 Module => $Module, 620 Required => 1, 621 }, 622 $Depends, 623 $NoColors 624 ); 625 } 626 } 627} 628 629sub _Check { 630 my ( $Module, $Depends, $NoColors ) = @_; 631 632 print " " x ( $Depends + 1 ); 633 print "o $Module->{Module}"; 634 my $Length = 33 - ( length( $Module->{Module} ) + ( $Depends * 2 ) ); 635 print '.' x $Length; 636 637 my $Version = Kernel::System::Environment->ModuleVersionGet( Module => $Module->{Module} ); 638 if ($Version) { 639 640 # cleanup version number 641 my $CleanedVersion = _VersionClean( 642 Version => $Version, 643 ); 644 645 my $ErrorMessage; 646 647 # Test if all module dependencies are installed by requiring the module. 648 # Don't do this for Net::DNS as it seems to take very long (>20s) in a 649 # mod_perl environment sometimes. 650 my %DontRequire = ( 651 'Net::DNS' => 1, 652 'Email::Valid' => 1, # uses Net::DNS internally 653 'Apache2::Reload' => 1, # is not needed / working on systems without mod_perl (like Plack etc.) 654 ); 655 656 ## no critic 657 if ( !$DontRequire{ $Module->{Module} } && !eval "require $Module->{Module}" ) { 658 $ErrorMessage .= 'Not all prerequisites for this module correctly installed. '; 659 } 660 ## use critic 661 662 if ( $Module->{VersionsNotSupported} ) { 663 664 my $VersionsNotSupported = 0; 665 ITEM: 666 for my $Item ( @{ $Module->{VersionsNotSupported} } ) { 667 668 # cleanup item version number 669 my $ItemVersion = _VersionClean( 670 Version => $Item->{Version}, 671 ); 672 673 if ( $CleanedVersion == $ItemVersion ) { 674 $VersionsNotSupported = $Item->{Comment}; 675 last ITEM; 676 } 677 } 678 679 if ($VersionsNotSupported) { 680 $ErrorMessage .= "Version $Version not supported! $VersionsNotSupported "; 681 } 682 } 683 684 my $AdditionalText = ''; 685 686 if ( $Module->{VersionsRecommended} ) { 687 688 my $VersionsRecommended = 0; 689 ITEM: 690 for my $Item ( @{ $Module->{VersionsRecommended} } ) { 691 692 my $ItemVersion = _VersionClean( 693 Version => $Item->{Version}, 694 ); 695 696 if ( $CleanedVersion < $ItemVersion ) { 697 $AdditionalText 698 .= " Please consider updating to version $Item->{Version} or higher: $Item->{Comment}\n"; 699 } 700 } 701 } 702 703 if ( $Module->{VersionRequired} ) { 704 705 # cleanup item version number 706 my $RequiredModuleVersion = _VersionClean( 707 Version => $Module->{VersionRequired}, 708 ); 709 710 if ( $CleanedVersion < $RequiredModuleVersion ) { 711 $ErrorMessage 712 .= "Version $Version installed but $Module->{VersionRequired} or higher is required! "; 713 } 714 } 715 716 if ($ErrorMessage) { 717 if ($NoColors) { 718 print "FAILED! $ErrorMessage\n"; 719 } 720 else { 721 print color('red') . 'FAILED!' . color('reset') . " $ErrorMessage\n"; 722 } 723 $ExitCode = 1; # error 724 } 725 else { 726 my $OutputVersion = $Version; 727 728 if ( $OutputVersion =~ m{ [0-9.] }xms ) { 729 $OutputVersion = 'v' . $OutputVersion; 730 } 731 732 if ($NoColors) { 733 print "ok ($OutputVersion)\n$AdditionalText"; 734 } 735 else { 736 print color('green') . 'ok' 737 . color('reset') 738 . " ($OutputVersion)\n" 739 . color('yellow') 740 . "$AdditionalText" 741 . color('reset'); 742 } 743 } 744 } 745 else { 746 my $Comment = $Module->{Comment} ? ' - ' . $Module->{Comment} : ''; 747 my $Required = $Module->{Required}; 748 my $Color = 'yellow'; 749 750 # OS Install Command 751 my %InstallCommand = _GetInstallCommand($Module); 752 753 # create example installation string for module 754 my $InstallText = ''; 755 if ( IsHashRefWithData( \%InstallCommand ) ) { 756 my $CMD = $InstallCommand{CMD}; 757 if ( $InstallCommand{SubCMD} ) { 758 $CMD = sprintf $InstallCommand{CMD}, $InstallCommand{SubCMD}; 759 } 760 761 $InstallText = " To install, you can use: '" . sprintf( $CMD, $InstallCommand{Package} ) . "'."; 762 } 763 764 if ($Required) { 765 $Required = 'required'; 766 $Color = 'red'; 767 $ExitCode = 1; # error 768 } 769 else { 770 $Required = 'optional'; 771 } 772 if ($NoColors) { 773 print "Not installed! ($Required $Comment)\n"; 774 } 775 else { 776 print color($Color) 777 . 'Not installed!' 778 . color('reset') 779 . "$InstallText ($Required$Comment)\n"; 780 } 781 } 782 783 if ( $Module->{Depends} ) { 784 for my $ModuleSub ( @{ $Module->{Depends} } ) { 785 _Check( $ModuleSub, $Depends + 1, $NoColors ); 786 } 787 } 788 789 return 1; 790} 791 792sub _PackageList { 793 my ($PackageList) = @_; 794 795 my $CMD; 796 my $SubCMD; 797 my @Packages; 798 799 # if we're on Windows we don't need to see Apache + mod_perl modules 800 MODULE: 801 for my $Module ( @{$PackageList} ) { 802 803 my $Required = $Module->{Required}; 804 my $Version = Kernel::System::Environment->ModuleVersionGet( Module => $Module->{Module} ); 805 if ( !$Version ) { 806 my %InstallCommand = _GetInstallCommand($Module); 807 808 if ( $Module->{Depends} ) { 809 810 MODULESUB: 811 for my $ModuleSub ( @{ $Module->{Depends} } ) { 812 my $Required = $Module->{Required}; 813 my %InstallCommandSub = _GetInstallCommand($ModuleSub); 814 815 next MODULESUB if !IsHashRefWithData( \%InstallCommandSub ); 816 next MODULESUB if !$Required; 817 818 push @Packages, $InstallCommandSub{Package}; 819 } 820 } 821 822 next MODULE if !IsHashRefWithData( \%InstallCommand ); 823 next MODULE if !$Required; 824 825 $CMD = $InstallCommand{CMD}; 826 $SubCMD = $InstallCommand{SubCMD}; 827 push @Packages, $InstallCommand{Package}; 828 } 829 } 830 831 return ( 832 CMD => $CMD, 833 SubCMD => $SubCMD, 834 Packages => \@Packages, 835 ); 836} 837 838sub _VersionClean { 839 my (%Param) = @_; 840 841 return 0 if !$Param{Version}; 842 return 0 if $Param{Version} eq 'undef'; 843 844 # replace all special characters with an dot 845 $Param{Version} =~ s{ [_-] }{.}xmsg; 846 847 my @VersionParts = split q{\.}, $Param{Version}; 848 849 my $CleanedVersion = ''; 850 for my $Count ( 0 .. 4 ) { 851 $VersionParts[$Count] ||= 0; 852 $CleanedVersion .= sprintf "%04d", $VersionParts[$Count]; 853 } 854 855 return int $CleanedVersion; 856} 857 858sub _GetInstallCommand { 859 my ($Module) = @_; 860 my $CMD; 861 my $SubCMD; 862 my $Package; 863 864 # returns the installation type e.g. ppm 865 my $InstType = $DistToInstType{$OSDist}; 866 my $OuputInstall = 1; 867 868 if ($InstType) { 869 870 # gets the install command for installation type 871 # e.g. ppm install %s 872 # default is the cpan install command 873 # e.g. cpan %s 874 $CMD = $InstTypeToCMD{$InstType}->{CMD}; 875 $SubCMD = $InstTypeToCMD{$InstType}->{SubCMD}; 876 877 # gets the target package 878 if ( 879 exists $Module->{InstTypes}->{$InstType} 880 && !defined $Module->{InstTypes}->{$InstType} 881 ) 882 { 883 # if we a hash key for the installation type but a undefined value 884 # then we prevent the output for the installation command 885 $OuputInstall = 0; 886 } 887 elsif ( $InstTypeToCMD{$InstType}->{UseModule} ) { 888 889 # default is the cpan module name 890 $Package = $Module->{Module}; 891 } 892 else { 893 # if the package name is defined for the installation type 894 # e.g. ppm then we use this as package name 895 $Package = $Module->{InstTypes}->{$InstType}; 896 } 897 } 898 899 return if !$OuputInstall; 900 901 if ( !$CMD || !$Package ) { 902 $CMD = $InstTypeToCMD{default}->{CMD}; 903 $SubCMD = $InstTypeToCMD{default}->{SubCMD}; 904 $Package = $Module->{Module}; 905 } 906 907 return ( 908 CMD => $CMD, 909 SubCMD => $SubCMD, 910 Package => $Package, 911 ); 912} 913 914exit $ExitCode; 915