1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4# 5# This Source Code Form is "Incompatible With Secondary Licenses", as 6# defined by the Mozilla Public License, v. 2.0. 7 8package Bugzilla::Install::Requirements; 9 10# NOTE: This package MUST NOT "use" any Bugzilla modules other than 11# Bugzilla::Constants, anywhere. We may "use" standard perl modules. 12# 13# Subroutines may "require" and "import" from modules, but they 14# MUST NOT "use." 15 16use strict; 17use version; 18 19use Bugzilla::Constants; 20use Bugzilla::Install::Util qw(vers_cmp install_string bin_loc 21 extension_requirement_packages); 22use List::Util qw(max); 23use Term::ANSIColor; 24 25# Return::Value 1.666002 pollutes the error log with warnings about this 26# deprecated module. We have to set NO_CLUCK = 1 before loading Email::Send 27# in have_vers() to disable these warnings. 28BEGIN { 29 $Return::Value::NO_CLUCK = 1; 30} 31 32use base qw(Exporter); 33our @EXPORT = qw( 34 REQUIRED_MODULES 35 OPTIONAL_MODULES 36 FEATURE_FILES 37 38 check_requirements 39 check_graphviz 40 have_vers 41 install_command 42 map_files_to_features 43); 44 45# This is how many *'s are in the top of each "box" message printed 46# by checksetup.pl. 47use constant TABLE_WIDTH => 71; 48 49# Optional Apache modules that have no Perl component to them. 50# If these are installed, Bugzilla has additional functionality. 51# 52# The keys are the names of the modules, the values are what the module 53# is called in the output of "apachectl -t -D DUMP_MODULES". 54use constant APACHE_MODULES => { 55 mod_headers => 'headers_module', 56 mod_env => 'env_module', 57 mod_expires => 'expires_module', 58}; 59 60# These are all of the binaries that we could possibly use that can 61# give us info about which Apache modules are installed. 62# If we can't use "apachectl", the "httpd" binary itself takes the same 63# parameters. Note that on Debian and Gentoo, there is an "apache2ctl", 64# but it takes different parameters on each of those two distros, so we 65# don't use apache2ctl. 66use constant APACHE => qw(apachectl httpd apache2 apache); 67 68# If we don't find any of the above binaries in the normal PATH, 69# these are extra places we look. 70use constant APACHE_PATH => [qw( 71 /usr/sbin 72 /usr/local/sbin 73 /usr/libexec 74 /usr/local/libexec 75)]; 76 77# The below two constants are subroutines so that they can implement 78# a hook. Other than that they are actually constants. 79 80# "package" is the perl package we're checking for. "module" is the name 81# of the actual module we load with "require" to see if the package is 82# installed or not. "version" is the version we need, or 0 if we'll accept 83# any version. 84# 85# "blacklist" is an arrayref of regular expressions that describe versions that 86# are 'blacklisted'--that is, even if the version is high enough, Bugzilla 87# will refuse to say that it's OK to run with that version. 88sub REQUIRED_MODULES { 89 my $perl_ver = sprintf('%vd', $^V); 90 my @modules = ( 91 { 92 package => 'CGI.pm', 93 module => 'CGI', 94 # 3.51 fixes a security problem that affects Bugzilla. 95 # (bug 591165) 96 version => '3.51', 97 }, 98 { 99 package => 'Digest-SHA', 100 module => 'Digest::SHA', 101 version => 0 102 }, 103 # 0.23 fixes incorrect handling of 1/2 & 3/4 timezones. 104 { 105 package => 'TimeDate', 106 module => 'Date::Format', 107 version => '2.23' 108 }, 109 # 0.28 fixed some important bugs in DateTime. 110 { 111 package => 'DateTime', 112 module => 'DateTime', 113 version => '0.28' 114 }, 115 # 0.79 is required to work on Windows Vista and Windows Server 2008. 116 # As correctly detecting the flavor of Windows is not easy, 117 # we require this version for all Windows installations. 118 # 0.71 fixes a major bug affecting all platforms. 119 { 120 package => 'DateTime-TimeZone', 121 module => 'DateTime::TimeZone', 122 version => ON_WINDOWS ? '0.79' : '0.71' 123 }, 124 # 1.54 is required for Perl 5.10+. It also makes DBD::Oracle happy. 125 { 126 package => 'DBI', 127 module => 'DBI', 128 version => (vers_cmp($perl_ver, '5.13.3') > -1) ? '1.614' : '1.54' 129 }, 130 # 2.22 fixes various problems related to UTF8 strings in hash keys, 131 # as well as line endings on Windows. 132 { 133 package => 'Template-Toolkit', 134 module => 'Template', 135 version => '2.22' 136 }, 137 # 2.04 implement the "Test" method (to write to data/mailer.testfile). 138 { 139 package => 'Email-Send', 140 module => 'Email::Send', 141 version => ON_WINDOWS ? '2.16' : '2.04', 142 blacklist => ['^2\.196$'] 143 }, 144 { 145 package => 'Email-MIME', 146 module => 'Email::MIME', 147 # This fixes a memory leak in walk_parts that affected jobqueue.pl. 148 version => '1.904' 149 }, 150 { 151 package => 'URI', 152 module => 'URI', 153 # This version properly handles a semicolon as the delimiter 154 # in a URL query string. 155 version => '1.37', 156 }, 157 # 0.32 fixes several memory leaks in the XS version of some functions. 158 { 159 package => 'List-MoreUtils', 160 module => 'List::MoreUtils', 161 version => 0.32, 162 }, 163 { 164 package => 'Math-Random-ISAAC', 165 module => 'Math::Random::ISAAC', 166 version => '1.0.1', 167 }, 168 ); 169 170 if (ON_WINDOWS) { 171 push(@modules, 172 { 173 package => 'Win32', 174 module => 'Win32', 175 # 0.35 fixes a memory leak in GetOSVersion, which we use. 176 version => 0.35, 177 }, 178 { 179 package => 'Win32-API', 180 module => 'Win32::API', 181 # 0.55 fixes a bug with char* that might affect Bugzilla::RNG. 182 version => '0.55', 183 }, 184 { 185 package => 'DateTime-TimeZone-Local-Win32', 186 module => 'DateTime::TimeZone::Local::Win32', 187 # We require DateTime::TimeZone 0.79, so this version must match. 188 version => '0.79', 189 } 190 ); 191 } 192 193 my $extra_modules = _get_extension_requirements('REQUIRED_MODULES'); 194 push(@modules, @$extra_modules); 195 return \@modules; 196}; 197 198sub OPTIONAL_MODULES { 199 my $perl_ver = sprintf('%vd', $^V); 200 my @modules = ( 201 { 202 package => 'GD', 203 module => 'GD', 204 version => '1.20', 205 feature => [qw(graphical_reports new_charts old_charts)], 206 }, 207 { 208 package => 'Chart', 209 module => 'Chart::Lines', 210 # Versions below 2.1 cannot be detected accurately. 211 # There is no 2.1.0 release (it was 2.1), but .0 is required to fix 212 # https://rt.cpan.org/Public/Bug/Display.html?id=28218. 213 version => '2.1.0', 214 feature => [qw(new_charts old_charts)], 215 }, 216 { 217 package => 'Template-GD', 218 # This module tells us whether or not Template-GD is installed 219 # on Template-Toolkits after 2.14, and still works with 2.14 and lower. 220 module => 'Template::Plugin::GD::Image', 221 version => 0, 222 feature => ['graphical_reports'], 223 }, 224 { 225 package => 'GDTextUtil', 226 module => 'GD::Text', 227 version => 0, 228 feature => ['graphical_reports'], 229 }, 230 { 231 package => 'GDGraph', 232 module => 'GD::Graph', 233 version => 0, 234 feature => ['graphical_reports'], 235 }, 236 { 237 package => 'MIME-tools', 238 # MIME::Parser is packaged as MIME::Tools on ActiveState Perl 239 module => ON_WINDOWS ? 'MIME::Tools' : 'MIME::Parser', 240 version => '5.406', 241 feature => ['moving'], 242 }, 243 { 244 package => 'libwww-perl', 245 module => 'LWP::UserAgent', 246 version => 0, 247 feature => ['updates'], 248 }, 249 { 250 package => 'XML-Twig', 251 module => 'XML::Twig', 252 version => 0, 253 feature => ['moving', 'updates'], 254 }, 255 { 256 package => 'PatchReader', 257 module => 'PatchReader', 258 # 0.9.6 fixes two notable bugs and significantly improves the UX. 259 version => '0.9.6', 260 feature => ['patch_viewer'], 261 }, 262 { 263 package => 'perl-ldap', 264 module => 'Net::LDAP', 265 version => 0, 266 feature => ['auth_ldap'], 267 }, 268 { 269 package => 'Authen-SASL', 270 module => 'Authen::SASL', 271 version => 0, 272 feature => ['smtp_auth'], 273 }, 274 { 275 package => 'Net-SMTP-SSL', 276 module => 'Net::SMTP::SSL', 277 version => 1.01, 278 feature => ['smtp_ssl'], 279 }, 280 { 281 package => 'RadiusPerl', 282 module => 'Authen::Radius', 283 version => 0, 284 feature => ['auth_radius'], 285 }, 286 # XXX - Once we require XMLRPC::Lite 0.717 or higher, we can 287 # remove SOAP::Lite from the list. 288 { 289 package => 'SOAP-Lite', 290 module => 'SOAP::Lite', 291 # Fixes various bugs, including 542931 and 552353 + stops 292 # throwing warnings with Perl 5.12. 293 version => '0.712', 294 feature => ['xmlrpc'], 295 }, 296 # Since SOAP::Lite 1.0, XMLRPC::Lite is no longer included 297 # and so it must be checked separately. 298 { 299 package => 'XMLRPC-Lite', 300 module => 'XMLRPC::Lite', 301 version => '0.712', 302 feature => ['xmlrpc'], 303 }, 304 { 305 package => 'JSON-RPC', 306 module => 'JSON::RPC', 307 version => 0, 308 feature => ['jsonrpc'], 309 }, 310 { 311 package => 'JSON-XS', 312 module => 'JSON::XS', 313 # 2.0 is the first version that will work with JSON::RPC. 314 version => '2.0', 315 feature => ['jsonrpc_faster'], 316 }, 317 { 318 package => 'Test-Taint', 319 module => 'Test::Taint', 320 version => 0, 321 feature => ['jsonrpc', 'xmlrpc'], 322 }, 323 { 324 # We need the 'utf8_mode' method of HTML::Parser, for HTML::Scrubber. 325 package => 'HTML-Parser', 326 module => 'HTML::Parser', 327 version => (vers_cmp($perl_ver, '5.13.3') > -1) ? '3.67' : '3.40', 328 feature => ['html_desc'], 329 }, 330 { 331 package => 'HTML-Scrubber', 332 module => 'HTML::Scrubber', 333 version => 0, 334 feature => ['html_desc'], 335 }, 336 { 337 # we need version 2.21 of Encode for mime_name 338 package => 'Encode', 339 module => 'Encode', 340 version => 2.21, 341 feature => ['detect_charset'], 342 }, 343 { 344 package => 'Encode-Detect', 345 module => 'Encode::Detect', 346 version => 0, 347 feature => ['detect_charset'], 348 }, 349 350 # Inbound Email 351 { 352 package => 'Email-Reply', 353 module => 'Email::Reply', 354 version => 0, 355 feature => ['inbound_email'], 356 }, 357 { 358 package => 'HTML-FormatText-WithLinks', 359 module => 'HTML::FormatText::WithLinks', 360 # We need 0.13 to set the "bold" marker to "*". 361 version => '0.13', 362 feature => ['inbound_email'], 363 }, 364 365 # Mail Queueing 366 { 367 package => 'TheSchwartz', 368 module => 'TheSchwartz', 369 # 1.07 supports the prioritization of jobs. 370 version => 1.07, 371 feature => ['jobqueue'], 372 }, 373 { 374 package => 'Daemon-Generic', 375 module => 'Daemon::Generic', 376 version => 0, 377 feature => ['jobqueue'], 378 }, 379 { 380 package => 'File-Slurp', 381 module => 'File::Slurp', 382 version => '9999.13', 383 feature => ['jobqueue'], 384 }, 385 386 # mod_perl 387 { 388 package => 'mod_perl', 389 module => 'mod_perl2', 390 version => '1.999022', 391 feature => ['mod_perl'], 392 }, 393 { 394 package => 'Apache-SizeLimit', 395 module => 'Apache2::SizeLimit', 396 # 0.96 properly determines process size on Linux. 397 version => '0.96', 398 feature => ['mod_perl'], 399 }, 400 401 # typesniffer 402 { 403 package => 'File-MimeInfo', 404 module => 'File::MimeInfo::Magic', 405 version => '0', 406 feature => ['typesniffer'], 407 }, 408 { 409 package => 'IO-stringy', 410 module => 'IO::Scalar', 411 version => '0', 412 feature => ['typesniffer'], 413 }, 414 ); 415 416 my $extra_modules = _get_extension_requirements('OPTIONAL_MODULES'); 417 push(@modules, @$extra_modules); 418 return \@modules; 419}; 420 421# This maps features to the files that require that feature in order 422# to compile. It is used by t/001compile.t and mod_perl.pl. 423use constant FEATURE_FILES => ( 424 jsonrpc => ['Bugzilla/WebService/Server/JSONRPC.pm', 'jsonrpc.cgi'], 425 xmlrpc => ['Bugzilla/WebService/Server/XMLRPC.pm', 'xmlrpc.cgi', 426 'Bugzilla/WebService.pm', 'Bugzilla/WebService/*.pm'], 427 moving => ['importxml.pl'], 428 auth_ldap => ['Bugzilla/Auth/Verify/LDAP.pm'], 429 auth_radius => ['Bugzilla/Auth/Verify/RADIUS.pm'], 430 inbound_email => ['email_in.pl'], 431 jobqueue => ['Bugzilla/Job/*', 'Bugzilla/JobQueue.pm', 432 'Bugzilla/JobQueue/*', 'jobqueue.pl'], 433 patch_viewer => ['Bugzilla/Attachment/PatchReader.pm'], 434 updates => ['Bugzilla/Update.pm'], 435); 436 437# This implements the REQUIRED_MODULES and OPTIONAL_MODULES stuff 438# described in in Bugzilla::Extension. 439sub _get_extension_requirements { 440 my ($function) = @_; 441 442 my $packages = extension_requirement_packages(); 443 my @modules; 444 foreach my $package (@$packages) { 445 if ($package->can($function)) { 446 my $extra_modules = $package->$function; 447 push(@modules, @$extra_modules); 448 } 449 } 450 return \@modules; 451}; 452 453sub check_requirements { 454 my ($output) = @_; 455 456 print "\n", install_string('checking_modules'), "\n" if $output; 457 my $root = ROOT_USER; 458 my $missing = _check_missing(REQUIRED_MODULES, $output); 459 460 print "\n", install_string('checking_dbd'), "\n" if $output; 461 my $have_one_dbd = 0; 462 my $db_modules = DB_MODULE; 463 foreach my $db (keys %$db_modules) { 464 my $dbd = $db_modules->{$db}->{dbd}; 465 $have_one_dbd = 1 if have_vers($dbd, $output); 466 } 467 468 print "\n", install_string('checking_optional'), "\n" if $output; 469 my $missing_optional = _check_missing(OPTIONAL_MODULES, $output); 470 471 my $missing_apache = _missing_apache_modules(APACHE_MODULES, $output); 472 473 # If we're running on Windows, reset the input line terminator so that 474 # console input works properly - loading CGI tends to mess it up 475 $/ = "\015\012" if ON_WINDOWS; 476 477 my $pass = !scalar(@$missing) && $have_one_dbd; 478 return { 479 pass => $pass, 480 one_dbd => $have_one_dbd, 481 missing => $missing, 482 optional => $missing_optional, 483 apache => $missing_apache, 484 any_missing => !$pass || scalar(@$missing_optional), 485 }; 486} 487 488# A helper for check_requirements 489sub _check_missing { 490 my ($modules, $output) = @_; 491 492 my @missing; 493 foreach my $module (@$modules) { 494 unless (have_vers($module, $output)) { 495 push(@missing, $module); 496 } 497 } 498 499 return \@missing; 500} 501 502sub _missing_apache_modules { 503 my ($modules, $output) = @_; 504 my $apachectl = _get_apachectl(); 505 return [] if !$apachectl; 506 my $command = "$apachectl -t -D DUMP_MODULES"; 507 my $cmd_info = `$command 2>&1`; 508 # If apachectl returned a value greater than 0, then there was an 509 # error parsing Apache's configuration, and we can't check modules. 510 my $retval = $?; 511 if ($retval > 0) { 512 print STDERR install_string('apachectl_failed', 513 { command => $command, root => ROOT_USER }), "\n"; 514 return []; 515 } 516 my @missing; 517 foreach my $module (keys %$modules) { 518 my $ok = _check_apache_module($module, $modules->{$module}, 519 $cmd_info, $output); 520 push(@missing, $module) if !$ok; 521 } 522 return \@missing; 523} 524 525sub _get_apachectl { 526 foreach my $bin_name (APACHE) { 527 my $bin = bin_loc($bin_name); 528 return $bin if $bin; 529 } 530 # Try again with a possibly different path. 531 foreach my $bin_name (APACHE) { 532 my $bin = bin_loc($bin_name, APACHE_PATH); 533 return $bin if $bin; 534 } 535 return undef; 536} 537 538sub _check_apache_module { 539 my ($module, $config_name, $mod_info, $output) = @_; 540 my $ok; 541 if ($mod_info =~ /^\s+\Q$config_name\E\b/m) { 542 $ok = 1; 543 } 544 if ($output) { 545 _checking_for({ package => $module, ok => $ok }); 546 } 547 return $ok; 548} 549 550sub print_module_instructions { 551 my ($check_results, $output) = @_; 552 553 # First we print the long explanatory messages. 554 555 if (scalar @{$check_results->{missing}}) { 556 print install_string('modules_message_required'); 557 } 558 559 if (!$check_results->{one_dbd}) { 560 print install_string('modules_message_db'); 561 } 562 563 if (my @missing = @{$check_results->{optional}} and $output) { 564 print install_string('modules_message_optional'); 565 # Now we have to determine how large the table cols will be. 566 my $longest_name = max(map(length($_->{package}), @missing)); 567 568 # The first column header is at least 11 characters long. 569 $longest_name = 11 if $longest_name < 11; 570 571 # The table is TABLE_WIDTH characters long. There are seven mandatory 572 # characters (* and space) in the string. So, we have a total 573 # of TABLE_WIDTH - 7 characters to work with. 574 my $remaining_space = (TABLE_WIDTH - 7) - $longest_name; 575 print '*' x TABLE_WIDTH . "\n"; 576 printf "* \%${longest_name}s * %-${remaining_space}s *\n", 577 'MODULE NAME', 'ENABLES FEATURE(S)'; 578 print '*' x TABLE_WIDTH . "\n"; 579 foreach my $package (@missing) { 580 printf "* \%${longest_name}s * %-${remaining_space}s *\n", 581 $package->{package}, 582 _translate_feature($package->{feature}); 583 } 584 } 585 586 if (my @missing = @{ $check_results->{apache} }) { 587 print install_string('modules_message_apache'); 588 my $missing_string = join(', ', @missing); 589 my $size = TABLE_WIDTH - 7; 590 printf "* \%-${size}s *\n", $missing_string; 591 my $spaces = TABLE_WIDTH - 2; 592 print "*", (' ' x $spaces), "*\n"; 593 } 594 595 my $need_module_instructions = 596 ( (!$output and @{$check_results->{missing}}) 597 or ($output and $check_results->{any_missing}) ) ? 1 : 0; 598 599 if ($need_module_instructions or @{ $check_results->{apache} }) { 600 # If any output was required, we want to close the "table" 601 print "*" x TABLE_WIDTH . "\n"; 602 } 603 604 # And now we print the actual installation commands. 605 606 if (my @missing = @{$check_results->{optional}} and $output) { 607 print install_string('commands_optional') . "\n\n"; 608 foreach my $module (@missing) { 609 my $command = install_command($module); 610 printf "%15s: $command\n", $module->{package}; 611 } 612 print "\n"; 613 } 614 615 if (!$check_results->{one_dbd}) { 616 print install_string('commands_dbd') . "\n"; 617 my %db_modules = %{DB_MODULE()}; 618 foreach my $db (keys %db_modules) { 619 my $command = install_command($db_modules{$db}->{dbd}); 620 printf "%10s: \%s\n", $db_modules{$db}->{name}, $command; 621 } 622 print "\n"; 623 } 624 625 if (my @missing = @{$check_results->{missing}}) { 626 print colored(install_string('commands_required'), COLOR_ERROR), "\n"; 627 foreach my $package (@missing) { 628 my $command = install_command($package); 629 print " $command\n"; 630 } 631 } 632 633 if ($output && $check_results->{any_missing} && !ON_ACTIVESTATE 634 && !$check_results->{hide_all}) 635 { 636 print install_string('install_all', { perl => $^X }); 637 } 638 if (!$check_results->{pass}) { 639 print colored(install_string('installation_failed'), COLOR_ERROR), 640 "\n\n"; 641 } 642} 643 644sub _translate_feature { 645 my $features = shift; 646 my @strings; 647 foreach my $feature (@$features) { 648 push(@strings, install_string("feature_$feature")); 649 } 650 return join(', ', @strings); 651} 652 653sub check_graphviz { 654 my ($output) = @_; 655 656 my $webdotbase = Bugzilla->params->{'webdotbase'}; 657 return 1 if $webdotbase =~ /^https?:/; 658 659 my $return; 660 $return = 1 if -x $webdotbase; 661 662 if ($output) { 663 _checking_for({ package => 'GraphViz', ok => $return }); 664 } 665 666 if (!$return) { 667 print install_string('bad_executable', { bin => $webdotbase }), "\n"; 668 } 669 670 my $webdotdir = bz_locations()->{'webdotdir'}; 671 # Check .htaccess allows access to generated images 672 if (-e "$webdotdir/.htaccess") { 673 my $htaccess = new IO::File("$webdotdir/.htaccess", 'r') 674 || die "$webdotdir/.htaccess: " . $!; 675 if (!grep(/png/, $htaccess->getlines)) { 676 print STDERR install_string('webdot_bad_htaccess', 677 { dir => $webdotdir }), "\n"; 678 } 679 $htaccess->close; 680 } 681 682 return $return; 683} 684 685# This was originally clipped from the libnet Makefile.PL, adapted here for 686# accurate version checking. 687sub have_vers { 688 my ($params, $output) = @_; 689 my $module = $params->{module}; 690 my $package = $params->{package}; 691 if (!$package) { 692 $package = $module; 693 $package =~ s/::/-/g; 694 } 695 my $wanted = $params->{version}; 696 697 eval "require $module;"; 698 # Don't let loading a module change the output-encoding of STDOUT 699 # or STDERR. (CGI.pm tries to set "binmode" on these file handles when 700 # it's loaded, and other modules may do the same in the future.) 701 Bugzilla::Install::Util::set_output_encoding(); 702 703 # VERSION is provided by UNIVERSAL::, and can be called even if 704 # the module isn't loaded. We eval'uate ->VERSION because it can die 705 # when the version is not valid (yes, this happens from time to time). 706 # In that case, we use an uglier method to get the version. 707 my $vnum = eval { $module->VERSION }; 708 if ($@) { 709 no strict 'refs'; 710 $vnum = ${"${module}::VERSION"}; 711 712 # If we come here, then the version is not a valid one. 713 # We try to sanitize it. 714 if ($vnum =~ /^((\d+)(\.\d+)*)/) { 715 $vnum = $1; 716 } 717 } 718 $vnum ||= -1; 719 720 # Must do a string comparison as $vnum may be of the form 5.10.1. 721 my $vok = ($vnum ne '-1' && version->new($vnum) >= version->new($wanted)) ? 1 : 0; 722 my $blacklisted; 723 if ($vok && $params->{blacklist}) { 724 $blacklisted = grep($vnum =~ /$_/, @{$params->{blacklist}}); 725 $vok = 0 if $blacklisted; 726 } 727 728 if ($output) { 729 _checking_for({ 730 package => $package, ok => $vok, wanted => $wanted, 731 found => $vnum, blacklisted => $blacklisted 732 }); 733 } 734 735 return $vok ? 1 : 0; 736} 737 738sub _checking_for { 739 my ($params) = @_; 740 my ($package, $ok, $wanted, $blacklisted, $found) = 741 @$params{qw(package ok wanted blacklisted found)}; 742 743 my $ok_string = $ok ? install_string('module_ok') : ''; 744 745 # If we're actually checking versions (like for Perl modules), then 746 # we have some rather complex logic to determine what we want to 747 # show. If we're not checking versions (like for GraphViz) we just 748 # show "ok" or "not found". 749 if (exists $params->{found}) { 750 my $found_string; 751 # We do a string compare in case it's non-numeric. We make sure 752 # it's not a version object as negative versions are forbidden. 753 if ($found && !ref($found) && $found eq '-1') { 754 $found_string = install_string('module_not_found'); 755 } 756 elsif ($found) { 757 $found_string = install_string('module_found', { ver => $found }); 758 } 759 else { 760 $found_string = install_string('module_unknown_version'); 761 } 762 $ok_string = $ok ? "$ok_string: $found_string" : $found_string; 763 } 764 elsif (!$ok) { 765 $ok_string = install_string('module_not_found'); 766 } 767 768 my $black_string = $blacklisted ? install_string('blacklisted') : ''; 769 my $want_string = $wanted ? "v$wanted" : install_string('any'); 770 771 my $str = sprintf "%s %20s %-11s $ok_string $black_string\n", 772 install_string('checking_for'), $package, "($want_string)"; 773 print $ok ? $str : colored($str, COLOR_ERROR); 774} 775 776sub install_command { 777 my $module = shift; 778 my ($command, $package); 779 780 if (ON_ACTIVESTATE) { 781 $command = 'ppm install %s'; 782 $package = $module->{package}; 783 } 784 else { 785 $command = "$^X install-module.pl \%s"; 786 # Non-Windows installations need to use module names, because 787 # CPAN doesn't understand package names. 788 $package = $module->{module}; 789 } 790 return sprintf $command, $package; 791} 792 793# This does a reverse mapping for FEATURE_FILES. 794sub map_files_to_features { 795 my %features = FEATURE_FILES; 796 my %files; 797 foreach my $feature (keys %features) { 798 my @my_files = @{ $features{$feature} }; 799 foreach my $pattern (@my_files) { 800 foreach my $file (glob $pattern) { 801 $files{$file} = $feature; 802 } 803 } 804 } 805 return \%files; 806} 807 8081; 809 810__END__ 811 812=head1 NAME 813 814Bugzilla::Install::Requirements - Functions and variables dealing 815 with Bugzilla's perl-module requirements. 816 817=head1 DESCRIPTION 818 819This module is used primarily by C<checksetup.pl> to determine whether 820or not all of Bugzilla's prerequisites are installed. (That is, all the 821perl modules it requires.) 822 823=head1 CONSTANTS 824 825=over 826 827=item C<REQUIRED_MODULES> 828 829An arrayref of hashrefs that describes the perl modules required by 830Bugzilla. The hashes have three keys: 831 832=over 833 834=item C<package> - The name of the Perl package that you'd find on 835CPAN for this requirement. 836 837=item C<module> - The name of a module that can be passed to the 838C<install> command in C<CPAN.pm> to install this module. 839 840=item C<version> - The version of this module that we require, or C<0> 841if any version is acceptable. 842 843=back 844 845=item C<OPTIONAL_MODULES> 846 847An arrayref of hashrefs that describes the perl modules that add 848additional features to Bugzilla if installed. Its hashes have all 849the fields of L</REQUIRED_MODULES>, plus a C<feature> item--an arrayref 850of strings that describe what features require this module. 851 852=item C<FEATURE_FILES> 853 854A hashref that describes what files should only be compiled if a certain 855feature is enabled. The feature is the key, and the values are arrayrefs 856of file names (which are passed to C<glob>, so shell patterns work). 857 858=back 859 860 861=head1 SUBROUTINES 862 863=over 4 864 865=item C<check_requirements> 866 867=over 868 869=item B<Description> 870 871This checks what optional or required perl modules are installed, like 872C<checksetup.pl> does. 873 874=item B<Params> 875 876=over 877 878=item C<$output> - C<true> if you want the function to print out information 879about what it's doing, and the versions of everything installed. 880 881=back 882 883=item B<Returns> 884 885A hashref containing these values: 886 887=over 888 889=item C<pass> - Whether or not we have all the mandatory requirements. 890 891=item C<missing> - An arrayref containing any required modules that 892are not installed or that are not up-to-date. Each item in the array is 893a hashref in the format of items from L</REQUIRED_MODULES>. 894 895=item C<optional> - The same as C<missing>, but for optional modules. 896 897=item C<apache> - The name of each optional Apache module that is missing. 898 899=item C<have_one_dbd> - True if at least one C<DBD::> module is installed. 900 901=item C<any_missing> - True if there are any missing Perl modules, even 902optional modules. 903 904=back 905 906=back 907 908=item C<check_graphviz($output)> 909 910Description: Checks if the graphviz binary specified in the 911 C<webdotbase> parameter is a valid binary, or a valid URL. 912 913Params: C<$output> - C<$true> if you want the function to 914 print out information about what it's doing. 915 916Returns: C<1> if the check was successful, C<0> otherwise. 917 918=item C<have_vers($module, $output)> 919 920 Description: Tells you whether or not you have the appropriate 921 version of the module requested. It also prints 922 out a message to the user explaining the check 923 and the result. 924 925 Params: C<$module> - A hashref, in the format of an item from 926 L</REQUIRED_MODULES>. 927 C<$output> - Set to true if you want this function to 928 print information to STDOUT about what it's 929 doing. 930 931 Returns: C<1> if you have the module installed and you have the 932 appropriate version. C<0> otherwise. 933 934=item C<install_command($module)> 935 936 Description: Prints out the appropriate command to install the 937 module specified, depending on whether you're 938 on Windows or Linux. 939 940 Params: C<$module> - A hashref, in the format of an item from 941 L</REQUIRED_MODULES>. 942 943 Returns: nothing 944 945=item C<map_files_to_features> 946 947Returns a hashref where file names are the keys and the value is the feature 948that must be enabled in order to compile that file. 949 950=back 951